首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何为使用Vuex存储的Vue表单组件编写Jest单元测试?

如何为使用Vuex存储的Vue表单组件编写Jest单元测试?
EN

Stack Overflow用户
提问于 2018-05-08 12:09:07
回答 1查看 13.5K关注 0票数 9

我有一份登录表格。当我用数据填写登录表单并单击登录按钮时:

  • 表单数据(用户名、密码)发送到服务器,并返回响应。
  • 如果表单数据无效,则<flash-message>组件将显示消息。
  • 如果表单数据有效,则将用户重定向到仪表板。

由于这个组件严重依赖于Vuex存储,所以我无法为这个组件想出一些有效的测试用例。

  • 这个组件可测试吗?
  • 如果它是可测试的,我如何用玩笑编写单元测试?
  • 我应该嘲笑我的组件中的哪一部分?
  • 应该使用vue-test-utils挂载/浅安装方法包装组件吗?
  • 我的组件使用引导-Vue UI组件。我该怎么对付他们?

我没有JavaScript生态系统的经验,所以我希望能给出详细的解释。

Login.vue

代码语言:javascript
复制
<template>
  <b-col sm="6" offset-sm="3">
    <h1><span class="fa fa-sign-in"></span> Login</h1>
    <flash-message></flash-message>
    <!-- LOGIN FORM -->
    <div class="form">
        <b-form-group>
            <label>Email</label>
            <input type="text" class="form-control" name="email" v-model="email">
        </b-form-group>

        <b-form-group>
            <label>Password</label>
            <input type="password" class="form-control" name="password" v-model="password">
        </b-form-group>

        <b-btn type="submit" variant="warning" size="lg" @click="login">Login</b-btn>
    </div>

    <hr>

    <p>Need an account? <b-link :to="{name:'signup'}">Signup</b-link></p>
    <p>Or go <b-link :to="{name:'home'}">home</b-link>.</p>
  </b-col>

</template>

<script>
export default {
  data () {
    return {
      email: '',
      password: ''
    }
  },
  methods: {
    async login () {
      this.$store.dispatch('login', {data: {email: this.email, password: this.password}, $router: this.$router})
    }
  }
}
</script>
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-05-08 17:28:46

Vue测试用例文档说:

我们建议编写测试,以断言组件的公共接口,并将其内部视为黑匣子。单个测试用例将断言向组件提供的某些输入(用户交互或支持的更改)将导致预期的输出(呈现结果或发出的自定义事件)。

所以我们不应该测试引导-vue组件,这是该项目的维护人员的工作。

编写包含单元测试的代码

为了更容易地测试组件,将它们的范围限定在它们单独的责任范围内将有帮助。这意味着登录表单应该是它自己的证监会(单个文件组件),而登录页面是另一个使用该登录表单的证监会。

在这里,我们将登录表单与登录页面隔离开来。

代码语言:javascript
复制
<template>
    <div class="form">
        <b-form-group>
            <label>Email</label>
            <input type="text" class="form-control" 
                   name="email" v-model="email">
        </b-form-group>

        <b-form-group>
            <label>Password</label>
            <input type="password" class="form-control" 
                   name="password" v-model="password">
        </b-form-group>

        <b-btn type="submit" variant="warning" 
               size="lg" @click="login">
               Login
        </b-btn>
    </div>
</template>

<script>
export default {
    data() {
        return { email: '', password: '' };
    },
    methods: {
        login() {
            this.$store.dispatch('login', {
                email: this.email,
                password: this.password
            }).then(() => { /* success */ }, () => { /* failure */ });
        }
    }
}
</script>

我从存储操作分派中删除了路由器,因为当登录成功或失败时,处理重定向不是存储的责任。商店不应该知道在它前面有一个前厅。它处理与数据相关的数据和异步请求。

独立测试每一部分

单独测试商店的操作。然后,它们就可以在组件中被完全模仿。

测试存储操作

在这里,我们想确保商店做它想做的事。因此,我们可以检查状态是否有正确的数据,是否在模拟HTTP调用时发出HTTP调用。

代码语言:javascript
复制
import Vuex from 'vuex';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import storeConfig from '@/store/config';

describe('actions', () => {
    let http;
    let store;

    beforeAll(() => {
        http = new MockAdapter(axios);
        store = new Vuex.Store(storeConfig());
    });

    afterEach(() => {
        http.reset();
    });

    afterAll(() => {
        http.restore();
    });

    it('calls login and sets the flash messages', () => {
        const fakeData = { /* ... */ };
        http.onPost('api/login').reply(200, { data: fakeData });
        return store.dispatch('login')
            .then(() => expect(store.state.messages).toHaveLength(1));
    });
    // etc.
});

测试我们的简单LoginForm

当调用submit按钮时,这个组件所做的唯一真实的事情就是分派login动作。所以我们应该测试一下这个。我们不需要测试动作本身,因为它已经单独测试过了。

代码语言:javascript
复制
import Vuex from 'vuex';
import { mount, createLocalVue } from '@vue/test-utils';
import LoginForm from '@/components/LoginForm';

const localVue = createLocalVue();
localVue.use(Vuex);

describe('Login form', () => {

    it('calls the login action correctly', () => {
        const loginMock = jest.fn(() => Promise.resolve());
        const store = new Vuex.Store({
            actions: {
                // mock function
                login: loginMock
            }
        });
        const wrapper = mount(LoginForm, { localVue, store });
        wrapper.find('button').trigger('click');
        expect(loginMock).toHaveBeenCalled();
    });
});

测试闪存消息组件

同样,我们应该使用注入的消息来模拟存储状态,并通过测试每个消息项、类等的存在来确保FlashMessage组件正确地显示消息。

测试登录页面

登录页面组件现在可以只是一个容器,所以没有什么需要测试的。

代码语言:javascript
复制
<template>
    <b-col sm="6" offset-sm="3">
        <h1><span class="fa fa-sign-in"></span> Login</h1>
        <flash-message />
        <!-- LOGIN FORM -->
        <login-form />
        <hr>
        <login-nav />
    </b-col>
</template>

<script>
import FlashMessage from '@/components/FlashMessage';
import LoginForm from '@/components/LoginForm';
import LoginNav from '@/components/LoginNav';

export default {
    components: {
        FlashMessage,
        LoginForm,
        LoginNav,
    }
}
</script>

何时使用mountshallow

shallow说:

mount类似,它创建了一个包含已挂载和呈现的Vue组件的Wrapper,但是带有存根的子组件。

这意味着来自容器组件的子组件将被替换为<!-- -->注释,并且它们的所有交互性都不会存在。因此,它将被测试的组件与其子程序可能具有的所有需求隔离开来。

然后,登录页面的插入DOM将几乎为空,其中将替换FlashMessageLoginFormLoginNav组件:

代码语言:javascript
复制
<b-col sm="6" offset-sm="3">
    <h1><span class="fa fa-sign-in"></span> Login</h1>
    <!-- -->
    <!-- LOGIN FORM -->
    <!-- -->
    <hr>
    <!-- -->
</b-col>
票数 31
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50233263

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档