Jest测试submit事件报TypeError: Cannot read property 'value' of undefined如何解决
错误原因
你的selectDestination函数中没有从事件对象的target属性取值,而是直接通过document.querySelector('form')获取页面表单元素。测试运行在Node.js的jsdom环境下,默认没有你写的表单DOM结构,所以querySelector返回null,访问null.destination.value就会抛出"Cannot read property 'value' of undefined"的错误。
解决方案1:不修改原业务代码,测试前挂载DOM
在测试用例执行前,把对应的表单HTML插入到测试环境的DOM中即可,调整后的测试代码如下:
describe('submit event', () => { it('listens for event when submit button pressed', () => { // 先挂载表单DOM到测试环境,设置默认选中的option值为1 document.body.innerHTML = ` <form> <label for="event">Choose a destination</label> <select name="destination" id="destination"> <option value="1" selected>Paris</option> </select> <input id="submit" type="submit"> </form> ` // 模拟事件只需要带preventDefault即可,原业务代码没有用到e.target const fakeE = { preventDefault: jest.fn() } // mock全局fetch避免测试时报请求相关错误 global.fetch = jest.fn(() => Promise.resolve({ json: () => Promise.resolve({}) }) ) app.selectDestination(fakeE) expect(app.selectDestination).toHaveBeenCalled() // 可选补充验证逻辑 expect(fakeE.preventDefault).toHaveBeenCalled() expect(global.fetch).toHaveBeenCalledWith('http://localhost:3000/data/1') }) })
解决方案2:优化原业务代码,提升可测试性
直接从提交事件的target获取表单元素(提交事件触发时e.target就是表单本身),不需要全局查询DOM,耦合度更低、可测试性更强,调整后的代码如下:
修改后的业务代码
const selectDestination = (e) => { e.preventDefault(); // 替换原来的document.querySelector逻辑,直接从事件对象取表单 let form = e.target; const destination = { id: form.destination.value } console.log(destination) fetch(`http://localhost:3000/data/${destination.id}`) .then(r => r.json()) .then(appendPrice) .catch(console.warn) }
调整后的测试代码
describe('submit event', () => { it('listens for event when submit button pressed', () => { const fakeE = { preventDefault: jest.fn(), target: { destination : { value: '1' }, } } global.fetch = jest.fn(() => Promise.resolve({ json: () => Promise.resolve({}) }) ) app.selectDestination(fakeE) expect(app.selectDestination).toHaveBeenCalled() }) })
内容的提问来源于stack exchange,提问作者Valortome
相关产品推荐
相关产品推荐

