不变违规:找不到“商店"在“Connect(SportsDatabase)"的上下文或道具中; [英] Invariant Violation: Could not find "store" in either the context or props of "Connect(SportsDatabase)"

查看:18
本文介绍了不变违规:找不到“商店"在“Connect(SportsDatabase)"的上下文或道具中;的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

完整代码在这里:https://gist.github.com/js08/0ec3d70dfda76d7e9fb4

  • 我有一个应用程序,它根据构建环境显示不同的桌面和移动模板.
  • 我能够成功地在需要隐藏移动模板导航菜单的地方开发它.
  • 现在我可以编写一个测试用例,它通过 proptypes 获取所有值并正确呈现
  • 但不确定如何在其移动设备不呈现导航组件时编写单元测试用例.
  • 我试过了,但我遇到了错误...你能告诉我如何解决它吗.
  • 在下面提供代码.

测试用例

import {expect} from 'chai';从反应"导入反应;从'react-addons-test-utils'导入TestUtils;从'../../../src/components/sports-top-portion/sports-top-portion.jsx'导入{SportsTopPortion};require('../../test-utils/dom');描述('运动顶部"单元测试',函数(){让shallowRenderer = TestUtils.createRenderer();让sportsContentContainerLayout ='移动';让sportsContentContainerProfile = {'exists': 'hasSidebar'};让sportsContentContainerAuthExchange = {hasValidAccessToken: true};让sportsContentContainerHasValidAccessToken ='test';it('应该正确渲染', () => {shallowRenderer.render(<SportsTopPortionsportsWholeFramework={sportsContentContainerLayout}sportsPlayers={sportsContentContainerProfile}sportsAuthentication={sportsContentContainerAuthExchange}sportsUpperBar={{activeSportsLink:'test'}}/>);//shallowRenderer.render(<SportsTopPortionsportsWholeFramework={sportsContentContainerLayout}sportsPlayers={sportsContentContainerProfile} hasValidAccessToken={sportsContentContainerHasValidAccessToken}/>);让渲染元素 = 浅渲染器.getRenderOutput();console.log("renderedElement------->" + JSON.stringify(renderedElement));期望(renderedElement).to.exist;});it('当sports.build 是移动的时不应该渲染sportsNavigationComponent', () => {letsportsNavigationComponent = TestUtils.renderIntoDocument(<SportsTopPortionsportsWholeFramework={sportsContentContainerLayout}sportsPlayers={sportsContentContainerProfile}sportsAuthentication={sportsContentContainerAuthExchange}sportsUpperBar={{activeSportsLink:'test'}}/>);console.log("sportsNavigationComponent------->" + JSON.stringify(sportsNavigationComponent));//let footnoteContainer = TestUtils.findRenderedDOMComponentWithClass(sportsNavigationComponent, 'linkPack--standard');//expect(footnoteContainer).to.exist;});});

需要编写测试用例的代码片段

if (sports.build === 'mobile') {sportsNavigationComponent = 

;sportsSideMEnu = <div/>;searchComponent =

;sportsPlayersWidget = <div/>;}

错误

1) 当sports.build 是移动的时,sports-top-partion"单元测试不应该渲染sportsNavigationComponent:不变违规:无法在Connect(SportsDatabase)"的上下文或道具中找到store".要么将根组件包装在 <Provider> 中,要么将store"作为道具显式传递给Connect(SportsDatabase)".在 Object.invariant [作为默认值] (C:sports-whole-page
ode_modulesinvariantinvariant.js:42:15)在新连接 (C:sports-whole-page
ode_modules
eact-reduxlibcomponentscreateConnect.js:135:33)在 [object Object].ReactCompositeComponentMixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactCompositeComponent.js:148:18)在 [object Object].wrapper [as mountComponent] (C:sports-whole-page
ode_modules
eactlibReactPerf.js:66:21)在 Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)在 ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:sports-whole-page
ode_modules
eactlibReactMultiChild.js:241:44)在 ReactDOMComponent.Mixin._createContentMarkup (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:591:32)在 ReactDOMComponent.Mixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:479:29)在 Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)在 ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:sports-whole-page
ode_modules
eactlibReactMultiChild.js:241:44)在 ReactDOMComponent.Mixin._createContentMarkup (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:591:32)在 ReactDOMComponent.Mixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:479:29)在 Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)在 [object Object].ReactCompositeComponentMixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactCompositeComponent.js:225:34)在 [object Object].wrapper [as mountComponent] (C:sports-whole-page
ode_modules
eactlibReactPerf.js:66:21)在 Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)在 ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:sports-whole-page
ode_modules
eactlibReactMultiChild.js:241:44)在 ReactDOMComponent.Mixin._createContentMarkup (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:591:32)在 ReactDOMComponent.Mixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:479:29)在 Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)在 [object Object].ReactCompositeComponentMixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactCompositeComponent.js:225:34)在 [object Object].wrapper [as mountComponent] (C:sports-whole-page
ode_modules
eactlibReactPerf.js:66:21)在 Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)在 ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:sports-whole-page
ode_modules
eactlibReactMultiChild.js:241:44)在 ReactDOMComponent.Mixin._createContentMarkup (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:591:32)在 ReactDOMComponent.Mixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:479:29)在 Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)在 [object Object].ReactCompositeComponentMixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactCompositeComponent.js:225:34)在 [object Object].wrapper [as mountComponent] (C:sports-whole-page
ode_modules
eactlibReactPerf.js:66:21)在 Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)在 [object Object].ReactCompositeComponentMixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactCompositeComponent.js:225:34)在 [object Object].wrapper [as mountComponent] (C:sports-whole-page
ode_modules
eactlibReactPerf.js:66:21)在 Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)在 mountComponentIntoNode (C:sports-whole-page
ode_modules
eactlibReactMount.js:266:32)在 ReactReconcileTransaction.Mixin.perform (C:sports-whole-page
ode_modules
eactlibTransaction.js:136:20)在 batchedMountComponentIntoNode (C:sports-whole-page
ode_modules
eactlibReactMount.js:282:15)在 ReactDefaultBatchingStrategyTransaction.Mixin.perform (C:sports-whole-page
ode_modules
eactlibTransaction.js:136:20)在 Object.ReactDefaultBatchingStrategy.batchedUpdates (C:sports-whole-page
ode_modules
eactlibReactDefaultBatchingStrategy.js:62:19)在 Object.batchedUpdates (C:sports-whole-page
ode_modules
eactlibReactUpdates.js:94:20)在 Object.ReactMount._renderNewRootComponent (C:sports-whole-page
ode_modules
eactlibReactMount.js:476:18)在 Object.wrapper [as _renderNewRootComponent] (C:sports-whole-page
ode_modules
eactlibReactPerf.js:66:21)在 Object.ReactMount._renderSubtreeIntoContainer (C:sports-whole-page
ode_modules
eactlibReactMount.js:550:32)在 Object.ReactMount.render (C:sports-whole-page
ode_modules
eactlibReactMount.js:570:23)在 Object.wrapper [as render] (C:sports-whole-page
ode_modules
eactlibReactPerf.js:66:21)在 Object.ReactTestUtils.renderIntoDocument (C:sports-whole-page
ode_modules
eactlibReactTestUtils.js:76:21)在上下文中.<匿名>(C:/codebase/sports-whole-page/test/components/sports-top-portion/sports-top-portion-unit-tests.js:28:41)在 callFn (C:sports-whole-page
ode_modulesmochalib
unnable.js:286:21)在 Test.Runnable.run (C:sports-whole-page
ode_modulesmochalib
unnable.js:279:7)在 Runner.runTest (C:sports-whole-page
ode_modulesmochalib
unner.js:421:10)在 C:sports-whole-page
ode_modulesmochalib
unner.js:528:12接下来 (C:sports-whole-page
ode_modulesmochalib
unner.js:341:14)在 C:sports-whole-page
ode_modulesmochalib
unner.js:351:7接下来 (C:sports-whole-page
ode_modulesmochalib
unner.js:283:14)在 Immediate._onImmediate (C:sports-whole-page
ode_modulesmochalib
unner.js:319:5)

解决方案

很简单.您正在尝试测试通过调用 connect()(MyPlainComponent) 生成的包装器组件.该包装器组件希望能够访问 Redux 存储.通常,该存储可作为 context.store 使用,因为在组件层次结构的顶部,您会有一个 <Provider store={myStore}/>.但是,您自己渲染连接的组件,没有存储,因此会引发错误.

您有几个选择:

  • 创建一个 store 并在你连接的组件周围渲染一个
  • 创建一个 store 并直接将其作为 <MyConnectedComponent store={store}/> 传入,因为连接的组件也会接受store"作为 prop
  • 不要费心测试连接的组件.导出普通"、未连接的版本,然后对其进行测试.如果您测试您的普通组件和您的 mapStateToProps 函数,您可以放心地假设连接的版本将正常工作.

您可能想通读 Redux 文档中的测试"页面:https://redux.js.org/recipes/writing-tests.

编辑:

实际看到您发布的源代码并重新阅读错误消息后,真正的问题不在于 SportsTopPane 组件.问题是您正在尝试完全"渲染 SportsTopPane,它也会渲染其所有子项,而不是像第一种情况那样进行浅"渲染.searchComponent = <SportsDatabase sportsWholeFramework="desktop"/> 正在渲染一个我认为也已连接的组件,因此期望在 React 的上下文"功能中提供一个商店.

此时,您有两个新选项:

  • 仅对 SportsTopPane 进行浅层"渲染,这样您就不会强迫它完全渲染其子项
  • 如果您确实想要对 SportsTopPane 进行深度"渲染,则需要在上下文中提供 Redux 存储.我强烈建议您查看酶测试库,它可以让您做到这一点.请参阅 http://airbnb.io/enzyme/docs/api/ReactWrapper/setContext.html 示例.

总的来说,我会注意到您可能试图在这个组件中做太多事情,并且可能想要考虑将它分解成更小的部分,每个组件的逻辑更少.

Full code here: https://gist.github.com/js08/0ec3d70dfda76d7e9fb4

Hi,

  • I have an application where it shows different templates for desktop and mobile on basis of build environment.
  • I am successfully able to develop it where I need to hide the navigation menu for my mobile template.
  • right now I am able to write one test case where it fetches all the values through the proptypes and renders correctly
  • but not sure how to write the unit test cases when its mobile it should not render nav component.
  • I tried but I am facing an error...can you tell me how to fix it.
  • provding code below.

Test case

import {expect} from 'chai';
import React from 'react';
import TestUtils from 'react-addons-test-utils';
import {SportsTopPortion} from '../../../src/components/sports-top-portion/sports-top-portion.jsx';
require('../../test-utils/dom');


describe('"sports-top-portion" Unit Tests', function() {
    let shallowRenderer = TestUtils.createRenderer();

    let sportsContentContainerLayout ='mobile';
    let sportsContentContainerProfile = {'exists': 'hasSidebar'};
    let sportsContentContainerAuthExchange = {hasValidAccessToken: true};
    let sportsContentContainerHasValidAccessToken ='test'; 

    it('should render correctly', () => {
        shallowRenderer.render(<SportsTopPortion sportsWholeFramework={sportsContentContainerLayout} sportsPlayers={sportsContentContainerProfile} sportsAuthentication={sportsContentContainerAuthExchange} sportsUpperBar={{activeSportsLink:'test'}} />);
        //shallowRenderer.render(<SportsTopPortion sportsWholeFramework={sportsContentContainerLayout} sportsPlayers={sportsContentContainerProfile} hasValidAccessToken={sportsContentContainerHasValidAccessToken}  />);

        let renderedElement = shallowRenderer.getRenderOutput();
        console.log("renderedElement------->" + JSON.stringify(renderedElement));

        expect(renderedElement).to.exist;
    });

    it('should not render sportsNavigationComponent when sports.build is mobile', () => {
        let sportsNavigationComponent = TestUtils.renderIntoDocument(<SportsTopPortion sportsWholeFramework={sportsContentContainerLayout} sportsPlayers={sportsContentContainerProfile} sportsAuthentication={sportsContentContainerAuthExchange} sportsUpperBar={{activeSportsLink:'test'}} />);
        console.log("sportsNavigationComponent------->" + JSON.stringify(sportsNavigationComponent));

        //let footnoteContainer = TestUtils.findRenderedDOMComponentWithClass(sportsNavigationComponent, 'linkPack--standard');

        //expect(footnoteContainer).to.exist;
    });

});

Code snippet where test case need to be written

if (sports.build === 'mobile') {
    sportsNavigationComponent = <div />;
    sportsSideMEnu = <div />;
    searchComponent = <div />;
    sportsPlayersWidget = <div />;
}

Error

1) "sports-top-portion" Unit Tests should not render sportsNavigationComponent when sports.build is mobile:
     Invariant Violation: Could not find "store" in either the context or props of "Connect(SportsDatabase)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(SportsDatabase)".
      at Object.invariant [as default] (C:sports-whole-page
ode_modulesinvariantinvariant.js:42:15)
      at new Connect (C:sports-whole-page
ode_modules
eact-reduxlibcomponentscreateConnect.js:135:33)
      at [object Object].ReactCompositeComponentMixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactCompositeComponent.js:148:18)
      at [object Object].wrapper [as mountComponent] (C:sports-whole-page
ode_modules
eactlibReactPerf.js:66:21)
      at Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)
      at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:sports-whole-page
ode_modules
eactlibReactMultiChild.js:241:44)
      at ReactDOMComponent.Mixin._createContentMarkup (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:591:32)
      at ReactDOMComponent.Mixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:479:29)
      at Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)
      at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:sports-whole-page
ode_modules
eactlibReactMultiChild.js:241:44)
      at ReactDOMComponent.Mixin._createContentMarkup (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:591:32)
      at ReactDOMComponent.Mixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:479:29)
      at Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)
      at [object Object].ReactCompositeComponentMixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactCompositeComponent.js:225:34)
      at [object Object].wrapper [as mountComponent] (C:sports-whole-page
ode_modules
eactlibReactPerf.js:66:21)
      at Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)
      at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:sports-whole-page
ode_modules
eactlibReactMultiChild.js:241:44)
      at ReactDOMComponent.Mixin._createContentMarkup (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:591:32)
      at ReactDOMComponent.Mixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:479:29)
      at Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)
      at [object Object].ReactCompositeComponentMixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactCompositeComponent.js:225:34)
      at [object Object].wrapper [as mountComponent] (C:sports-whole-page
ode_modules
eactlibReactPerf.js:66:21)
      at Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)
      at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:sports-whole-page
ode_modules
eactlibReactMultiChild.js:241:44)
      at ReactDOMComponent.Mixin._createContentMarkup (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:591:32)
      at ReactDOMComponent.Mixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactDOMComponent.js:479:29)
      at Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)
      at [object Object].ReactCompositeComponentMixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactCompositeComponent.js:225:34)
      at [object Object].wrapper [as mountComponent] (C:sports-whole-page
ode_modules
eactlibReactPerf.js:66:21)
      at Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)
      at [object Object].ReactCompositeComponentMixin.mountComponent (C:sports-whole-page
ode_modules
eactlibReactCompositeComponent.js:225:34)
      at [object Object].wrapper [as mountComponent] (C:sports-whole-page
ode_modules
eactlibReactPerf.js:66:21)
      at Object.ReactReconciler.mountComponent (C:sports-whole-page
ode_modules
eactlibReactReconciler.js:37:35)
      at mountComponentIntoNode (C:sports-whole-page
ode_modules
eactlibReactMount.js:266:32)
      at ReactReconcileTransaction.Mixin.perform (C:sports-whole-page
ode_modules
eactlibTransaction.js:136:20)
      at batchedMountComponentIntoNode (C:sports-whole-page
ode_modules
eactlibReactMount.js:282:15)
      at ReactDefaultBatchingStrategyTransaction.Mixin.perform (C:sports-whole-page
ode_modules
eactlibTransaction.js:136:20)
      at Object.ReactDefaultBatchingStrategy.batchedUpdates (C:sports-whole-page
ode_modules
eactlibReactDefaultBatchingStrategy.js:62:19)
      at Object.batchedUpdates (C:sports-whole-page
ode_modules
eactlibReactUpdates.js:94:20)
      at Object.ReactMount._renderNewRootComponent (C:sports-whole-page
ode_modules
eactlibReactMount.js:476:18)
      at Object.wrapper [as _renderNewRootComponent] (C:sports-whole-page
ode_modules
eactlibReactPerf.js:66:21)
      at Object.ReactMount._renderSubtreeIntoContainer (C:sports-whole-page
ode_modules
eactlibReactMount.js:550:32)
      at Object.ReactMount.render (C:sports-whole-page
ode_modules
eactlibReactMount.js:570:23)
      at Object.wrapper [as render] (C:sports-whole-page
ode_modules
eactlibReactPerf.js:66:21)
      at Object.ReactTestUtils.renderIntoDocument (C:sports-whole-page
ode_modules
eactlibReactTestUtils.js:76:21)
      at Context.<anonymous> (C:/codebase/sports-whole-page/test/components/sports-top-portion/sports-top-portion-unit-tests.js:28:41)
      at callFn (C:sports-whole-page
ode_modulesmochalib
unnable.js:286:21)
      at Test.Runnable.run (C:sports-whole-page
ode_modulesmochalib
unnable.js:279:7)
      at Runner.runTest (C:sports-whole-page
ode_modulesmochalib
unner.js:421:10)
      at C:sports-whole-page
ode_modulesmochalib
unner.js:528:12
      at next (C:sports-whole-page
ode_modulesmochalib
unner.js:341:14)
      at C:sports-whole-page
ode_modulesmochalib
unner.js:351:7
      at next (C:sports-whole-page
ode_modulesmochalib
unner.js:283:14)
      at Immediate._onImmediate (C:sports-whole-page
ode_modulesmochalib
unner.js:319:5)

解决方案

It's pretty simple. You're trying to test the wrapper component generated by calling connect()(MyPlainComponent). That wrapper component expects to have access to a Redux store. Normally that store is available as context.store, because at the top of your component hierarchy you'd have a <Provider store={myStore} />. However, you're rendering your connected component by itself, with no store, so it's throwing an error.

You've got a few options:

  • Create a store and render a <Provider> around your connected component
  • Create a store and directly pass it in as <MyConnectedComponent store={store} /> , as the connected component will also accept "store" as a prop
  • Don't bother testing the connected component. Export the "plain", unconnected version, and test that instead. If you test your plain component and your mapStateToProps function, you can safely assume the connected version will work correctly.

You probably want to read through the "Testing" page in the Redux docs: https://redux.js.org/recipes/writing-tests.

edit:

After actually seeing that you posted source, and re-reading the error message, the real problem is not with the SportsTopPane component. The problem is that you're trying to "fully" render SportsTopPane, which also renders all of its children, rather than doing a "shallow" render like you were in the first case. The line searchComponent = <SportsDatabase sportsWholeFramework="desktop" />; is rendering a component that I assume is also connected, and therefore expects a store to be available in React's "context" feature.

At this point, you have two new options:

  • Only do "shallow" rendering of SportsTopPane, so that you're not forcing it to fully render its children
  • If you do want to do "deep" rendering of SportsTopPane, you'll need to provide a Redux store in context. I highly suggest you take a look at the Enzyme testing library, which lets you do exactly that. See http://airbnb.io/enzyme/docs/api/ReactWrapper/setContext.html for an example.

Overall, I would note that you might be trying to do too much in this one component and might want to consider breaking it into smaller pieces with less logic per component.

这篇关于不变违规:找不到“商店"在“Connect(SportsDatabase)"的上下文或道具中;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆