Vue Router无法使用Jest从内部单元测试导航

时间:2019-11-07 10:32:28

标签: vue.js jestjs vue-router

我有一个路由器,“主页”,“登录”组件和“登录”组件的单元测试。

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

该逻辑在浏览器中工作正常,但是,当我运行单元测试时,出现异常:抛出:未定义,一旦登录组件尝试使用this.$router.push('/');

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

trying to route /login /

然后一旦我运行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 Component from 'vue-class-component';
import { axios } from '../plugins/axios';

@Component
export default class App extends Vue {
  private credentials = {
    email: '',
    password: '',
  };
  private error = '';
  private async login() {
    try {
      const data = await axios.post('http://localhost:5000/api/v1/user/auth', this.credentials);
      const token = data.data.payload;
      this.$store.dispatch('setUser', { token });
      this.error = '';
      this.$router.push('/');
    } catch (error) {
      console.warn(error);
      this.error = error;
    }
  }
}

以及单元测试:

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('/');
  });

});

0 个答案:

没有答案