Vue.js Vue路由器无法使用jest从内部单元测试导航

Vue.js Vue路由器无法使用jest从内部单元测试导航,vue.js,jestjs,vue-router,Vue.js,Jestjs,Vue Router,我有一个路由器,家庭,登录组件和登录组件的单元测试 逻辑是:当用户未经身份验证时,将其发送到登录页面,一旦用户通过身份验证,将其发送到主页 该逻辑在浏览器中运行良好,但是,当我运行单元测试时,我会遇到一个异常:抛出:未定义一旦登录组件尝试使用this.$router.push('/')导航 在控制台中,我看到消息: 尝试路由/登录/ 然后,一旦我运行next(),就会抛出异常 我是否缺少一些设置,使路由器在测试环境中正常工作 或者:是否有方法模拟传递给导航卫士的next()函数 这是路由器: i

我有一个路由器,家庭,登录组件和登录组件的单元测试

逻辑是:当用户未经身份验证时,将其发送到登录页面,一旦用户通过身份验证,将其发送到主页

该逻辑在浏览器中运行良好,但是,当我运行单元测试时,我会遇到一个异常:抛出:未定义一旦登录组件尝试使用
this.$router.push('/')导航

在控制台中,我看到消息:

尝试路由/登录/

然后,一旦我运行
next(),就会抛出异常

我是否缺少一些设置,使路由器在测试环境中正常工作

或者:是否有方法模拟传递给导航卫士的next()函数

这是路由器:

import VueRouter from 'vue-router';
import Home from '@/views/Home.vue';
import Login from '@/views/Login.vue';
import { state } from '@/store';

export const routes = [
  {
    path: '/',
    name: 'home',
    component: Home,
  },
  {
    path: '/login',
    name: 'login',
    component: Login,
    meta: {
      noAuthRequired: true,
    },
  },
];

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes,
});

router.beforeEach((to: any, from: any, next: any) => {
  console.log('trying to route', from.fullPath, to.fullPath);
  const isAuthed = !!state.user.token;
  if (!to.meta.noAuth && !isAuthed) {
    next({ name: 'login' });
  } else {
    next();
  }
});

export default router;
组成部分(相关部分):

以及单元测试:

import Vue from 'vue';
import Vuetify from 'vuetify';
import AxiosMockAdapter from 'axios-mock-adapter';
import { Wrapper, shallowMount, createLocalVue } from '@vue/test-utils';
import flushPromises from 'flush-promises';
import Vuex, { Store } from 'vuex';
import { axios } from '@/plugins/axios';
import VTest from '@/plugins/directive-test';
import LoginPage from '@/views/Login.vue';
import { mainStore, state, IState } from '@/store';
import VueRouter from 'vue-router';
import router from '@/router';

describe('Login page tests', () => {
  let page: Wrapper<Vue>;
  let localStore: Store<IState>;
  const localVue = createLocalVue();
  const maxios = new AxiosMockAdapter(axios);
  const vuetify = new Vuetify();
  const errorMessage = 'Input payload validation failed';
  const emailError = 'Invalid Email format';
  const validData = {
    email: 'valid@email.com',
    password: 'test pass',
  };
  // in order for "click" action to submit the form,
  // the v-btn component must be stubbed out with an HTML button
  const VBtn = {
    template: '<button type="submit"/>',
  };
  localVue.use(Vuetify);
  localVue.directive('test', VTest);
  localVue.use(Vuex);
  localVue.use(VueRouter);  
  beforeAll(() => {
    maxios.onPost().reply((body: any) => {
      const jsonData = JSON.parse(body.data);
      if (jsonData.email !== validData.email) {
        return [400, {
          message: errorMessage,
          errors: { email: emailError },
        }];
      }
      return [200, { payload: 'valid-token' }];
    });
  });

  beforeEach(() => {
    try {
      localStore = new Vuex.Store({
        ...mainStore,
        state: JSON.parse(JSON.stringify(state)),
      });
      page = shallowMount(LoginPage, {
        store: localStore,
        router,
        localVue,
        vuetify,
        stubs: {
          VBtn,
        },
        attachToDocument: true,
        sync: false,
      });
    } catch (error) {
      console.warn(error);
    }
  });
  afterEach(() => {
    maxios.resetHistory();
    page.destroy();
  });

  const submitLoginForm = async (data: any) => {
    page.find('[test-id="LoginEmailField"]').vm.$emit('input', data.email);
    page.find('[test-id="LoginPasswordField"]').vm.$emit('input', data.password);
    page.find('[test-id="LoginBtn"]').trigger('click');    
    await flushPromises();
  };


  it('Redirects user to home page after successful auth', async () => {
    await submitLoginForm(validData);
    expect(page.vm.$route.path).toEqual('/');
  });

});
从“Vue”导入Vue;
从“Vuetify”导入Vuetify;
从“axios模拟适配器”导入AxiosMockAdapter;
从'@vue/test-utils'导入{Wrapper,shallowMount,createLocalVue};
从“冲洗承诺”进口冲洗液;
从“Vuex”导入Vuex,{Store};
从“@/plugins/axios”导入{axios};
从“@/plugins/directive test”导入VTest;
从“@/views/Login.vue”导入登录页面;
从“@/store”导入{mainStore,state,IState};
从“vue路由器”导入VueRouter;
从“@/router”导入路由器;
描述('登录页面测试',()=>{
让页面:包装器;
让localStore:Store;
const localVue=createLocalVue();
const maxios=新的AxiosMockAdapter(axios);
const vuetify=新vuetify();
const errorMessage='输入有效负载验证失败';
const emailError='无效的电子邮件格式';
常数validData={
电邮:'valid@email.com',
密码:“测试通过”,
};
//为了让“单击”操作提交表单,
//v-btn组件必须用HTML按钮删除
常数VBtn={
模板:“”,
};
localVue.use(Vuetify);
localVue.指令(“测试”,VTest);
localVue.use(Vuex);
localVue.use(VueRouter);
以前(()=>{
maxios.onPost().reply((正文:任意)=>{
const jsonData=JSON.parse(body.data);
如果(jsonData.email!==validData.email){
返回[400{
消息:errorMessage,
错误:{email:emailError},
}];
}
返回[200,{有效负载:'有效令牌'}];
});
});
在每个之前(()=>{
试一试{
localStore=新的Vuex.Store({
……中流砥柱,
state:JSON.parse(JSON.stringify(state)),
});
第页=浅装(登录页{
商店:本地商店,
路由器,
localVue,
vuetify,
存根:{
VBtn,
},
附件文档:正确,
同步:假,
});
}捕获(错误){
控制台。警告(错误);
}
});
之后(()=>{
maxios.resetHistory();
page.destroy();
});
const submitLoginForm=async(数据:any)=>{
page.find('[test id=“LoginEmailField”]').vm.$emit('input',data.email);
page.find('[test id=“LoginPasswordField”]').vm.$emit('input',data.password');
page.find('[test id=“LoginBtn”]')。触发器('click');
等待flushPromises();
};
它('成功身份验证后将用户重定向到主页',异步()=>{
等待提交信息(validData);
expect(page.vm.$route.path).toEqual('/');
});
});
import Vue from 'vue';
import Vuetify from 'vuetify';
import AxiosMockAdapter from 'axios-mock-adapter';
import { Wrapper, shallowMount, createLocalVue } from '@vue/test-utils';
import flushPromises from 'flush-promises';
import Vuex, { Store } from 'vuex';
import { axios } from '@/plugins/axios';
import VTest from '@/plugins/directive-test';
import LoginPage from '@/views/Login.vue';
import { mainStore, state, IState } from '@/store';
import VueRouter from 'vue-router';
import router from '@/router';

describe('Login page tests', () => {
  let page: Wrapper<Vue>;
  let localStore: Store<IState>;
  const localVue = createLocalVue();
  const maxios = new AxiosMockAdapter(axios);
  const vuetify = new Vuetify();
  const errorMessage = 'Input payload validation failed';
  const emailError = 'Invalid Email format';
  const validData = {
    email: 'valid@email.com',
    password: 'test pass',
  };
  // in order for "click" action to submit the form,
  // the v-btn component must be stubbed out with an HTML button
  const VBtn = {
    template: '<button type="submit"/>',
  };
  localVue.use(Vuetify);
  localVue.directive('test', VTest);
  localVue.use(Vuex);
  localVue.use(VueRouter);  
  beforeAll(() => {
    maxios.onPost().reply((body: any) => {
      const jsonData = JSON.parse(body.data);
      if (jsonData.email !== validData.email) {
        return [400, {
          message: errorMessage,
          errors: { email: emailError },
        }];
      }
      return [200, { payload: 'valid-token' }];
    });
  });

  beforeEach(() => {
    try {
      localStore = new Vuex.Store({
        ...mainStore,
        state: JSON.parse(JSON.stringify(state)),
      });
      page = shallowMount(LoginPage, {
        store: localStore,
        router,
        localVue,
        vuetify,
        stubs: {
          VBtn,
        },
        attachToDocument: true,
        sync: false,
      });
    } catch (error) {
      console.warn(error);
    }
  });
  afterEach(() => {
    maxios.resetHistory();
    page.destroy();
  });

  const submitLoginForm = async (data: any) => {
    page.find('[test-id="LoginEmailField"]').vm.$emit('input', data.email);
    page.find('[test-id="LoginPasswordField"]').vm.$emit('input', data.password);
    page.find('[test-id="LoginBtn"]').trigger('click');    
    await flushPromises();
  };


  it('Redirects user to home page after successful auth', async () => {
    await submitLoginForm(validData);
    expect(page.vm.$route.path).toEqual('/');
  });

});