开玩笑的酶,使用 mount(),document.getElementById() 在 _method 调用之后出现的组件上返回 null

新手上路,请多包涵

我的 jest+enzyme mount() 测试遇到了问题。我正在测试一个功能,它切换显示组件。

组件间切换:当 state.infoDisplayContent = 'mission' 一个 missionControl 组件挂载时,当 state.infoDisplayContent = 'profile' 其他组件进入:

 _modifyAgentStatus () {
    const { currentAgentProfile, agentsDatabase } = this.state;
    const agentToMod = currentAgentProfile;

    if (agentToMod.status === 'Free') {
        this.setState({
            infoDisplayContent: 'mission'
        });
        agentToMod.status = 'Waiting';
    } else if (agentToMod.status === 'Waiting') {
        const locationSelect = document.getElementById('missionLocationSelect');

        agentToMod.location = locationSelect[locationSelect.selectedIndex].innerText;
        agentToMod.status = 'On Mission';
        this.setState({
            infoDisplayContent: 'profile'
        });
    }
}

当我触发这个功能时,一切看起来都很好,这个测试运行良好,并且测试成功通过了所需的组件:

 import React from 'react';
import { mount } from 'enzyme';
import App from '../containers/App';

const result = mount(
    <App />
)

test('change mission controls', () => {
    expect(result.state().currentAgentProfile.status).toBe('Free');
    result.find('#statusController').simulate('click');
    expect(result.find('#missionControls')).toHaveLength(1);
    expect(result.find('#missionLocationSelect')).toHaveLength(1);
    expect(result.state().currentAgentProfile.status).toBe('Waiting');
});

But when I simulate onClick two times:

test('change mission controls', () => {
    expect(result.state().currentAgentProfile.status).toBe('Free');
    result.find('#statusController').simulate('click');
    expect(result.find('#missionControls')).toHaveLength(1);
    expect(result.find('#missionLocationSelect')).toHaveLength(1);
    expect(result.state().currentAgentProfile.status).toBe('Waiting');
    result.find('#statusController').simulate('click');
    expect(result.state().currentAgentProfile.status).toBe('On Mission');
});

我得到这个断言:

     TypeError: Cannot read property 'selectedIndex' of null

  at App._modifyAgentStatus (development/containers/App/index.js:251:68)
  at Object.invokeGuardedCallback [as invokeGuardedCallbackWithCatch] (node_modules/react-dom/lib/ReactErrorUtils.js:26:5)
  at executeDispatch (node_modules/react-dom/lib/EventPluginUtils.js:83:21)
  at Object.executeDispatchesInOrder (node_modules/react-dom/lib/EventPluginUtils.js:108:5)
  at executeDispatchesAndRelease (node_modules/react-dom/lib/EventPluginHub.js:43:22)
  at executeDispatchesAndReleaseSimulated (node_modules/react-dom/lib/EventPluginHub.js:51:10)
  at forEachAccumulated (node_modules/react-dom/lib/forEachAccumulated.js:26:8)
  at Object.processEventQueue (node_modules/react-dom/lib/EventPluginHub.js:255:7)
  at node_modules/react-dom/lib/ReactTestUtils.js:350:22
  at ReactDefaultBatchingStrategyTransaction.perform (node_modules/react-dom/lib/Transaction.js:140:20)
  at Object.batchedUpdates (node_modules/react-dom/lib/ReactDefaultBatchingStrategy.js:62:26)
  at Object.batchedUpdates (node_modules/react-dom/lib/ReactUpdates.js:97:27)
  at node_modules/react-dom/lib/ReactTestUtils.js:348:18
  at ReactWrapper.<anonymous> (node_modules/enzyme/build/ReactWrapper.js:776:11)
  at ReactWrapper.single (node_modules/enzyme/build/ReactWrapper.js:1421:25)
  at ReactWrapper.simulate (node_modules/enzyme/build/ReactWrapper.js:769:14)
  at Object.<anonymous> (development/tests/AgentProfile.test.js:26:38)
  at process._tickCallback (internal/process/next_tick.js:109:7)

很明显:

 document.getElementById('missionLocationSelect');

返回null,但我不明白为什么。正如我提到的,元素通过了测试。

 expect(result.find('#missionLocationSelect')).toHaveLength(1);

但无法使用 document.getElementById() 捕获。

请帮我解决这个问题并运行测试。

原文由 Dmytro Zhytomyrsky 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 531
2 个回答

感谢 https://stackoverflow.com/users/853560/lewis-chung 和 Google 之神找到了解决方案:

  1. 通过 attachTo 参数将我的组件附加到 DOM:
    const result = mount(
       <App />, { attachTo: document.body }
   );

  1. 将我的方法中的错误字符串更改为与元素对象一起使用的字符串
agentToMod.location = locationSelect.options[locationSelect.selectedIndex].text;` :

_modifyAgentStatus () {

    const { currentAgentProfile, agentsDatabase } = this.state;
    const agentToMod = currentAgentProfile;

    if (agentToMod.status === 'Free') {
        this.setState({
            infoDisplayContent: 'mission'
        });
        agentToMod.status = 'Waiting';
    } else if (agentToMod.status === 'Waiting') {
        const locationSelect = document.getElementById('missionLocationSelect');

        agentToMod.location = agentToMod.location = locationSelect.options[locationSelect.selectedIndex].text;
        agentToMod.status = 'On Mission';
        this.setState({
            infoDisplayContent: 'profile'
            });
        }
    }

原文由 Dmytro Zhytomyrsky 发布,翻译遵循 CC BY-SA 4.0 许可协议

attachTo: document.body 将生成警告:

警告:render():不鼓励将组件直接渲染到 document.body 中,因为它的子项经常被第三方脚本和浏览器扩展操作。这可能会导致微妙的协调问题。尝试渲染到为您的应用程序创建的容器元素中。

所以只需附加到容器元素而不是 document.body ,无需将其添加到全局 Window 对象

before(() => {
  // Avoid `attachTo: document.body` Warning
  const div = document.createElement('div');
  div.setAttribute('id', 'container');
  document.body.appendChild(div);
});

after(() => {
  const div = document.getElementById('container');
  if (div) {
    document.body.removeChild(div);
  }
});

it('should display all contents', () => {
  const wrapper = mount(<YourComponent/>,{ attachTo: document.getElementById('container') });
});

原文由 Tina Chen 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进