![](/img/trans.png)
[英]Vue, vuex: how to unit test a component with namespaced store and mocking?
[英]How to write Jest unit test for a Vue form component which uses a Vuex store?
我有一個登錄表單。 當我用數據填寫登錄表單並單擊登錄按鈕時:
<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>
[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>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.