【问题标题】:Enzyme can't shallow render because of an imported script using 'addEventListener'由于使用“addEventListener”的导入脚本,酶无法进行浅层渲染
【发布时间】:2019-04-16 15:55:07
【问题描述】:

长话短说,我有一个导入 vanilla.js 组件的 React 应用程序。该组件与 React 应用程序之外的 DOM 交互,但有时 React 应用程序需要使用该组件。当我尝试浅渲染导入 Login 组件的 React 组件时,Jest 挂断了 vanilla.js 登录组件中的“addEventListener”:

TypeError: Cannot read property 'addEventListener' of null

  90 |     }
  91 |
> 92 |     document.querySelector(config.selectors.loginModal).addEventListener('click', (e) => closeLogin(e));
     |     ^
  93 |     document.querySelector(config.selectors.loginClose).addEventListener('click', (e) => closeLogin(e));
  94 |   };

所以我有我的反应应用程序:

import React from 'react';
import Login from '../login';
const Component = () => {
  return (
    <h3>
      <span className='cc-stats-login-btn' onClick={(e) => 
      Login.openRegister(e, 'Statistics')}>Register</span>
      or
      <span className='cc-stats-login-btn' onClick={(e) => Login.openLogin(e, 'Statistics')}>login</span>
      to view advanced analytics and graphs
    </h3>
  );
};

该应用的测试目前如下所示:

document.body.innerHTML =
  '<div class="login-modal-bg">' +
  '  <div class="login-modal-close"></div>' +
  '</div>';

describe('<Component />', () => {
  test('renders', () => {
    const wrapper = shallow(
      <Component />
    );
    expect(wrapper.exists()).toBe(true);
  });
});

Jest 似乎失败的登录组件的 js:

const Login = (() => {
  const config = {
    selectors: {
      loginModal: '.login-modal-bg',
      loginClose: '.login-modal-close'
    }
  };

  [...]

  const initialize = () => {
    document.querySelector(config.selectors.loginModal).addEventListener('click', (e) => closeLogin(e));
    document.querySelector(config.selectors.loginClose).addEventListener('click', (e) => closeLogin(e));
  };
};

据我所知,根据 Jest 文档,我只需要一个简单的字符串作为“模拟 dom”,并且 addEventListener 应该可以工作。但我得到的只是上面的 TypeError。有什么想法吗?

【问题讨论】:

  • 可测试性是直接 DOM 访问在 React 中不是一个好主意的原因之一。我建议模拟 document.querySelector 调用而不是模拟 DOM。
  • 我同意直接 DOM 访问在 React 中不是很好。但由于与业务相关的决策非常陌生,这不是我能做的。我尝试了以下方法来模拟 document.querySelector,但都不起作用:document.querySelector = jest.fn();global.document.querySelector = jest.fn();global.document.querySelector.addEventListener = jest.fn();
  • 结果如何?
  • 总是同样的错误:TypeError: Cannot read property 'addEventListener' of null
  • 是的,这是一种反模式。我更新了答案。由于 addEventListener 甚至没有在被测试的组件中使用,所以甚至不需要打扰它。模拟整个登录模块并单独测试。

标签: javascript reactjs jestjs enzyme


【解决方案1】:

在单元测试中针对 DOM 进行测试(它在 Jest 中并不真实,因为它使用 JSDOM)提供了额外的移动部分。 document.querySelector 可以改为模拟:

const loginModalMock = jest.fn();
const loginCloseMock = jest.fn();

jest.spyOn(document, 'querySelector')
.mockReturnValue()
.mockReturnValueOnce({ addEventListener: loginModalMock })
.mockReturnValueOnce({ addEventListener: loginCloseMock })

const wrapper = shallow(
  <Component />
);

...

在这种特定情况下,document.querySelector 未在测试模块中使用。使用它的模块可以在测试文件的顶部模拟:

jest.mock('.../login', () => ({ openLogin: jest.fn() }));

【讨论】:

  • 我相信Login应该被更好地模拟,即使它被用于Component
猜你喜欢
  • 2017-10-20
  • 1970-01-01
  • 1970-01-01
  • 2018-09-25
  • 2020-04-20
  • 1970-01-01
  • 1970-01-01
  • 2020-08-26
  • 2019-02-16
相关资源
最近更新 更多