gpt4 book ai didi

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

转载 作者:搜寻专家 更新时间:2023-10-30 22:29:22 24 4
gpt4 key购买 nike

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

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

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

  • 这个组件可以测试吗?
  • 如果它可测试的,我该如何 Jest 编写单元测试?
  • 我应该模拟组件的哪一部分?
  • 我应该使用 vue-test-utils mount/shallowMount 方法来包装我的组件吗?
  • 我的组件使用 Bootstrap-Vue UI 组件。我该如何应对?

我没有使用 JavaScript 生态系统的经验,因此不胜感激。

登录.vue

<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>

最佳答案

Vue test utils documentation说:

[W]e recommend writing tests that assert your component's public interface, and treat its internals as a black box. A single test case would assert that some input (user interaction or change of props) provided to the component results in the expected output (render result or emitted custom events).

所以我们不应该测试 bootstrap-vue 组件,那是该项目维护者的工作。

编写代码时考虑单元测试

为了更轻松地测试组件,将它们的范围限定为它们的唯一责任会有所帮助。意思是登录表单应该是它自己的SFC(单文件组件),登录页面是另一个使用登录表单的SFC。

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

<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 调用。

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

这个组件做的唯一真正的事情是调度 login调用提交按钮时的操作。所以我们应该对此进行测试。我们不需要测试操作本身,因为它已经单独测试过了。

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

测试 flash 消息组件

以同样的方式,我们应该用注入(inject)的消息模拟商店状态,并确保 FlashMessage组件通过测试每个消息项、类等的存在来正确显示消息。

测试登录页面

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

<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>

何时使用mount对比shallow

documentation on shallow 说:

Like mount, it creates a Wrapper that contains the mounted and rendered Vue component, but with stubbed child components.

意味着来自容器组件的子组件将被替换为 <!-- -->评论和他们所有的互动都不会存在。因此它将被测试的组件与其子组件可能具有的所有要求隔离开来。

登录页面的插入 DOM 几乎是空的,其中 FlashMessage , LoginFormLoginNav组件将被替换:

<b-col sm="6" offset-sm="3">
<h1><span class="fa fa-sign-in"></span> Login</h1>
<!-- -->
<!-- LOGIN FORM -->
<!-- -->
<hr>
<!-- -->
</b-col>

关于javascript - 如何为使用 Vuex 存储的 Vue 表单组件编写 Jest 单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50233263/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com