如何在Jest单元测试中模拟ontouchStart以测试触屏场景?
在Jest中模拟触屏设备的正确测试方法
场景说明
我通过window对象的ontouchstart属性判断设备是否可触摸,据此给div元素添加对应类名,核心代码如下:
this.state = { touchable: true }; this.state.touchable = 'ontouchstart' in window; <div class={`${state.touchable ? 'touchable' : ''}`}> </div>
我需要编写单元测试验证触屏设备下div会带有touchable类名,之前尝试的测试代码如下:
describe('Given touch device', () => { beforeAll(() => { window.ontouchstart = jest.fn() }) it('should have class touchable', async () => { const { container } = await render(template, mockData) const container = container.querySelector('div') await waitFor(() => { expect(container).toHaveClass('touchable') }) }) })
正确的模拟与测试方案
1. 严谨模拟window属性
直接赋值window.ontouchstart可能会污染全局环境,更可靠的方式是用Object.defineProperty添加属性,测试后再清理:
describe('Given touch device', () => { beforeAll(() => { // 为window添加ontouchstart属性,模拟触屏设备 Object.defineProperty(window, 'ontouchstart', { value: jest.fn(), writable: true }); }); afterAll(() => { // 测试后删除属性,避免影响其他用例 delete window.ontouchstart; }); it('should render div with touchable class', () => { const { container } = render(template, mockData); // 修复变量重定义问题,改用不同变量名 const targetDiv = container.querySelector('div'); // 类名判断是同步逻辑,无需waitFor expect(targetDiv).toHaveClass('touchable'); }); });
2. 关键问题修正
- 变量重定义:原测试中
const container = container.querySelector('div')会导致变量冲突,需改成不同名称(如targetDiv)。 - 移除不必要的
waitFor:'ontouchstart' in window是同步判断,组件渲染时会直接计算类名,无需异步等待。
3. 补充非触屏场景测试(可选)
为覆盖全场景,可添加非触屏设备的测试用例:
describe('Given non-touch device', () => { beforeAll(() => { // 删除ontouchstart属性,模拟非触屏设备 delete window.ontouchstart; }); it('should not render div with touchable class', () => { const { container } = render(template, mockData); const targetDiv = container.querySelector('div'); expect(targetDiv).not.toHaveClass('touchable'); }); });
内容的提问来源于stack exchange,提问作者user20071510
相关产品推荐
相关产品推荐

