我有一个登录表单。当我用数据填写登录表单并单击登录按钮时:
<flash-message>
组件由于此组件在很大程度上取决于Vuex存储,因此我无法考虑此组件的某些有效测试用例。
我没有JavaScript生态系统的经验,所以请大家详细解释。
Login.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>
答案 0 :(得分:5)
Vue test utils documentation说:
[W]建议编写断言组件公共接口的测试,并将其内部视为黑盒子。单个测试用例会断言提供给组件的某些输入(用户交互或道具更改)会产生预期的输出(渲染结果或发出的自定义事件)。
所以我们不应该测试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.
});
此组件唯一真正的做法是在调用提交按钮时调度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();
});
});
同样,我们应该使用注入的消息模拟存储状态,并确保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
vs shallow
意味着容器组件中的子组件将被<!-- -->
注释替换,并且它们的所有交互性都不会存在。因此,它将被测试的组件与其孩子可能拥有的所有组件隔离开来。
登录页面的插入DOM几乎为空,其中FlashMessage
,LoginForm
和LoginNav
组件将被替换:
<b-col sm="6" offset-sm="3">
<h1><span class="fa fa-sign-in"></span> Login</h1>
<!-- -->
<!-- LOGIN FORM -->
<!-- -->
<hr>
<!-- -->
</b-col>