如何使用Vue Test Utils测试登录表单提交是否成功?
问题
我想知道如何测试登录是否成功?我有一个Login组件:
<template> <NavBar></NavBar> <div id="login"> <h1 style="text-align: center;">Login</h1> <form class="form"> <label class="form-label" for="username">Username</label> <br/> <input class="form-field" type="text" name="username" v-model="input.username" placeholder="Username" /> <br/> <label class="form-label" for="password">Password</label> <br/> <input class="form-field" type="password" name="password" v-model="input.password" placeholder="Password" /> <br/> <div style="text-align: center;" > <button class="form-field" type="button" v-on:click="login()">Login</button> </div> <br/> <span v-if="status==1">Authenticating...</span> </form> <div id="powered"> Powered by <a href="#">TinyDrive</a> </div> </div> </template> <script> import { store } from '../store'; import { api } from '../api'; import NavBar from '../components/NavBar.vue'; export default { name: 'Login', components: { NavBar }, data() { return { input: { password: '', username: '', }, status: 0, }; }, methods: { async login() { if (this.input.username != "" && this.input.password != "") { this.status = 1; //loading const response = await api.login(this.input.username, this.input.password); if (response.status == true) { store.setToken(response.token); store.setAuthenticated(true); this.$router.replace({ name: "filemanager" }); } else { console.log(response.message); } this.status = 0; //default } else { console.log("A username and password must be present"); } } } } </script>
我希望测试登录成功后渲染内容是否发生变化,编写了如下测试代码片段:
test('submit the form', async () => { const wrapper = mount(Login, { global: { plugins: [router] } }) expect(wrapper.html()).to.contain('class="form-field" type="text" name="username" placeholder="Username"') let username = wrapper.find("input[name=username]") username.element.value = 'test'; let password = wrapper.find("input[type=password]") password.element.value = 'test1234'; await wrapper.find('form').trigger('submit') //TODO: how do I test if either the rendered result or the current route? })
请问该如何完善测试代码,验证登录成功后的渲染结果或当前路由变化?
解决方案
1. 修正测试触发逻辑
你的登录按钮是type="button",绑定的是click事件,触发表单submit不会触发登录逻辑,需直接触发按钮点击。同时,修改输入框值后要同步v-model(用setValue方法自动触发input事件,而非直接修改element.value)。
2. Mock API 调用
测试时不能依赖真实后端接口,需mockapi.login返回成功结果:
import { api } from '../api'; jest.mock('../api', () => ({ api: { login: jest.fn().mockResolvedValue({ status: true, token: 'fake-token' }) } }));
3. 验证路由变化
可以通过检查router.currentRoute或断言路由replace方法的调用情况:
// 直接检查当前路由名称 expect(router.currentRoute.value.name).toBe('filemanager'); // 或用jest spy断言replace方法被正确调用 const replaceSpy = jest.spyOn(router, 'replace'); expect(replaceSpy).toHaveBeenCalledWith({ name: 'filemanager' });
4. 验证Store状态更新
通过jest spy监听store的setToken和setAuthenticated方法,确认登录成功后状态被正确设置:
import { store } from '../store'; const setTokenSpy = jest.spyOn(store, 'setToken'); const setAuthenticatedSpy = jest.spyOn(store, 'setAuthenticated'); // 登录后断言 expect(setTokenSpy).toHaveBeenCalledWith('fake-token'); expect(setAuthenticatedSpy).toHaveBeenCalledWith(true);
5. 验证渲染内容变化
登录成功后Login组件会被路由卸载,可断言组件内的登录表单元素不再存在:
expect(wrapper.find('input[name=username]').exists()).toBe(false); // 或直接断言组件已被销毁 expect(wrapper.exists()).toBe(false);
完整测试代码示例
import { mount } from '@vue/test-utils'; import Login from '../components/Login.vue'; import router from '../router'; import { api } from '../api'; import { store } from '../store'; // Mock API 登录接口 jest.mock('../api', () => ({ api: { login: jest.fn().mockResolvedValue({ status: true, token: 'fake-token' }) } })); test('successful login redirects to filemanager and updates store', async () => { // 监听store和路由的关键方法 const setTokenSpy = jest.spyOn(store, 'setToken'); const setAuthenticatedSpy = jest.spyOn(store, 'setAuthenticated'); const replaceSpy = jest.spyOn(router, 'replace'); // 挂载Login组件 const wrapper = mount(Login, { global: { plugins: [router] } }); // 设置输入框值并同步v-model await wrapper.find('input[name=username]').setValue('test'); await wrapper.find('input[type=password]').setValue('test1234'); // 触发登录按钮点击 await wrapper.find('button').trigger('click'); // 验证API调用参数正确 expect(api.login).toHaveBeenCalledWith('test', 'test1234'); // 验证Store状态更新 expect(setTokenSpy).toHaveBeenCalledWith('fake-token'); expect(setAuthenticatedSpy).toHaveBeenCalledWith(true); // 验证路由跳转 expect(replaceSpy).toHaveBeenCalledWith({ name: 'filemanager' }); expect(router.currentRoute.value.name).toBe('filemanager'); // 验证登录组件已卸载 expect(wrapper.exists()).toBe(false); });
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

