Vue3+Vitest组合API测试中,input触发焦点后activeElement为HTMLBodyElement问题
解决Vue测试中
document.activeElement指向body而非input的问题 问题重现
Vue组件代码
<template> <input id="input" type="text" @focus="handleOnFocus($event)" /> </template> <script setup type="ts"> const handleOnFocus = () => { console.log('Component document.activeElement:', document.activeElement) } </script>
测试代码
import { mount } from '@vue/test-utils' import { expect } from 'vitest' import AarghOmg from './AarghOmg.vue' describe('AarghOmg', () => { let wrapper: any beforeEach(() => { wrapper = mount<typeof AarghOmg>(AarghOmg, { attachTo: document.body }) }) it('outputs activeElement', () => { wrapper.find('#input').trigger('focus') console.log('Test document.body.innerHTML:', document.body.innerHTML) expect(true).toBe(true) }) })
控制台输出
Component document.activeElement: HTMLBodyElement {} Test document.body.innerHTML: <div data-v-app=""><input id="input" type="text"></div>
问题:浏览器中触发input焦点时,document.activeElement正常指向input,但测试环境中却指向body。
解决方案
1. 直接调用DOM元素的focus()方法
@vue/test-utils的trigger('focus')仅模拟事件派发,不会真正让元素获得焦点。改用DOM原生的focus()方法:
// 替换原有的trigger('focus') wrapper.find('#input').element.focus()
2. 配置测试环境支持视觉模拟
若使用jsdom(vitest默认环境),需开启pretendToBeVisual选项以支持焦点操作。在vitest.config.ts中添加:
export default defineConfig({ test: { environmentOptions: { jsdom: { pretendToBeVisual: true } } } })
3. 异步等待焦点状态更新
焦点操作可能涉及异步DOM更新,需用await配合nextTick确保状态生效:
it('outputs activeElement as input', async () => { const input = wrapper.find('#input') input.element.focus() await wrapper.vm.$nextTick() expect(document.activeElement).toBe(input.element) })
原理说明
trigger('focus')仅触发组件的focus事件回调,但不会修改浏览器(或测试环境)的实际焦点状态。而直接调用DOM元素的focus()方法会触发环境的焦点行为,同步更新document.activeElement的值。
内容的提问来源于stack exchange,提问作者mummybot
相关产品推荐
相关产品推荐

