source

불변 위반:Connect(SportsDatabase)의 컨텍스트 또는 소품에서 "스토어"를 찾을 수 없습니다.

bestscript 2023. 2. 8. 19:43

불변 위반:Connect(SportsDatabase)의 컨텍스트 또는 소품에서 "스토어"를 찾을 수 없습니다.

코드 상세: https://gist.github.com/js08/0ec3d70dfda76d7e9fb4

안녕하세요.

  • 빌드 환경에 따라 데스크톱과 모바일용 템플릿이 다르게 표시되는 애플리케이션을 사용하고 있습니다.
  • 모바일 템플릿의 네비게이션 메뉴를 숨길 필요가 있는 곳에서 성공적으로 개발할 수 있습니다.
  • 지금 나는 그것이 모든 값을 proptypes를 통해 가져오고 올바르게 렌더링하는 하나의 테스트 케이스를 쓸 수 있다.
  • 그러나 모바일에서 내비게이션 컴포넌트를 렌더링하지 않아야 할 경우 유닛 테스트 케이스를 어떻게 작성해야 하는지 잘 모르겠습니다.
  • 시도했지만 오류가 발생했습니다. 어떻게 고쳐야 하는지 알려주실 수 있나요?
  • 아래 코드 제공.

테스트 케이스

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;
    });

});

테스트 케이스를 기입할 필요가 있는 코드 스니펫

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

에러

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\node_modules\invariant\invariant.js:42:15)
      at new Connect (C:\sports-whole-page\node_modules\react-redux\lib\components\createConnect.js:135:33)
      at [object Object].ReactCompositeComponentMixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactCompositeComponent.js:148:18)
      at [object Object].wrapper [as mountComponent] (C:\sports-whole-page\node_modules\react\lib\ReactPerf.js:66:21)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:\sports-whole-page\node_modules\react\lib\ReactMultiChild.js:241:44)
      at ReactDOMComponent.Mixin._createContentMarkup (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:591:32)
      at ReactDOMComponent.Mixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:479:29)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:\sports-whole-page\node_modules\react\lib\ReactMultiChild.js:241:44)
      at ReactDOMComponent.Mixin._createContentMarkup (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:591:32)
      at ReactDOMComponent.Mixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:479:29)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at [object Object].ReactCompositeComponentMixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactCompositeComponent.js:225:34)
      at [object Object].wrapper [as mountComponent] (C:\sports-whole-page\node_modules\react\lib\ReactPerf.js:66:21)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:\sports-whole-page\node_modules\react\lib\ReactMultiChild.js:241:44)
      at ReactDOMComponent.Mixin._createContentMarkup (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:591:32)
      at ReactDOMComponent.Mixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:479:29)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at [object Object].ReactCompositeComponentMixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactCompositeComponent.js:225:34)
      at [object Object].wrapper [as mountComponent] (C:\sports-whole-page\node_modules\react\lib\ReactPerf.js:66:21)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:\sports-whole-page\node_modules\react\lib\ReactMultiChild.js:241:44)
      at ReactDOMComponent.Mixin._createContentMarkup (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:591:32)
      at ReactDOMComponent.Mixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:479:29)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at [object Object].ReactCompositeComponentMixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactCompositeComponent.js:225:34)
      at [object Object].wrapper [as mountComponent] (C:\sports-whole-page\node_modules\react\lib\ReactPerf.js:66:21)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at [object Object].ReactCompositeComponentMixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactCompositeComponent.js:225:34)
      at [object Object].wrapper [as mountComponent] (C:\sports-whole-page\node_modules\react\lib\ReactPerf.js:66:21)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at mountComponentIntoNode (C:\sports-whole-page\node_modules\react\lib\ReactMount.js:266:32)
      at ReactReconcileTransaction.Mixin.perform (C:\sports-whole-page\node_modules\react\lib\Transaction.js:136:20)
      at batchedMountComponentIntoNode (C:\sports-whole-page\node_modules\react\lib\ReactMount.js:282:15)
      at ReactDefaultBatchingStrategyTransaction.Mixin.perform (C:\sports-whole-page\node_modules\react\lib\Transaction.js:136:20)
      at Object.ReactDefaultBatchingStrategy.batchedUpdates (C:\sports-whole-page\node_modules\react\lib\ReactDefaultBatchingStrategy.js:62:19)
      at Object.batchedUpdates (C:\sports-whole-page\node_modules\react\lib\ReactUpdates.js:94:20)
      at Object.ReactMount._renderNewRootComponent (C:\sports-whole-page\node_modules\react\lib\ReactMount.js:476:18)
      at Object.wrapper [as _renderNewRootComponent] (C:\sports-whole-page\node_modules\react\lib\ReactPerf.js:66:21)
      at Object.ReactMount._renderSubtreeIntoContainer (C:\sports-whole-page\node_modules\react\lib\ReactMount.js:550:32)
      at Object.ReactMount.render (C:\sports-whole-page\node_modules\react\lib\ReactMount.js:570:23)
      at Object.wrapper [as render] (C:\sports-whole-page\node_modules\react\lib\ReactPerf.js:66:21)
      at Object.ReactTestUtils.renderIntoDocument (C:\sports-whole-page\node_modules\react\lib\ReactTestUtils.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\node_modules\mocha\lib\runnable.js:286:21)
      at Test.Runnable.run (C:\sports-whole-page\node_modules\mocha\lib\runnable.js:279:7)
      at Runner.runTest (C:\sports-whole-page\node_modules\mocha\lib\runner.js:421:10)
      at C:\sports-whole-page\node_modules\mocha\lib\runner.js:528:12
      at next (C:\sports-whole-page\node_modules\mocha\lib\runner.js:341:14)
      at C:\sports-whole-page\node_modules\mocha\lib\runner.js:351:7
      at next (C:\sports-whole-page\node_modules\mocha\lib\runner.js:283:14)
      at Immediate._onImmediate (C:\sports-whole-page\node_modules\mocha\lib\runner.js:319:5)

, 해서 생성.connect()(MyPlainComponent)래퍼 컴포넌트는 Redux 스토어에 액세스할 수 있어야 합니다.일반적으로 그 스토어는 다음과 같이 이용할 수 있습니다.context.store맨에는 「Component Hierarchy」라고 하는 「Component Hierarchy의 맨 위에는 "Component Hierarchy"가 <Provider store={myStore} />그러나 연결된 컴포넌트는 스토어 없이 단독으로 렌더링되므로 오류가 발생합니다.

몇 가지 옵션이 있습니다.

  • 스토어를 생성하여<Provider> connected component( 컴포넌트 주변)
  • 를 만들어 해 주세요.<MyConnectedComponent store={store} />는 "store"도로 받아들이기
  • 연결된 컴포넌트를 테스트할 필요가 없습니다.연결되지 않은 "일반" 버전을 내보내고 대신 테스트합니다. 와 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★mapStateToProps연결된 버전이 올바르게 작동한다고 가정할 수 있습니다.

Redux 문서의 "테스트 중" 페이지를 읽어보실 수 있습니다.https://redux.js.org/recipes/writing-tests

편집:

실제로 소스를 게시한 것을 확인하고 오류 메시지를 다시 읽으면 SportsTopPane 구성 요소에 문제가 없습니다.문제는 첫 번째 경우와 같이 "낮은" 렌더링을 하는 것이 아니라 "완전" 렌더링을 시도하고 있다는 것입니다. " " "searchComponent = <SportsDatabase sportsWholeFramework="desktop" />;는 연결되어 있다고 생각되는 컴포넌트를 렌더링하고 있기 때문에 React의 "콘텍스트" 기능으로 스토어를 사용할 수 있을 것으로 예상하고 있습니다.

이 시점에서는, 다음의 2개의 새로운 옵션이 있습니다.

  • SportsTopPane 렌더링만 "연기"하여 자식 렌더링을 강제하지 않도록 합니다.
  • SportsTopPane의 "깊이" 렌더링을 수행하려면 컨텍스트에서 Redux 저장소를 제공해야 합니다.정확히 그렇게 할 수 있는 효소 검사 라이브러리를 보시길 강력히 권합니다.예에 대해서는, http://airbnb.io/enzyme/docs/api/ReactWrapper/setContext.html 를 참조해 주세요.

전체적으로 이 컴포넌트 하나에 너무 많은 작업을 하려고 할 수 있으므로 컴포넌트당 로직이 적은 소규모로 분할하는 것을 검토해 주십시오.

농담으로 내게 효과가 있었던 가능한 해결책

import React from "react";
import { shallow } from "enzyme";
import { Provider } from "react-redux";
import configureMockStore from "redux-mock-store";
import TestPage from "../TestPage";

const mockStore = configureMockStore();
const store = mockStore({});

describe("Testpage Component", () => {
    it("should render without throwing an error", () => {
        expect(
            shallow(
                <Provider store={store}>
                    <TestPage />
                </Provider>
            ).exists(<h1>Test page</h1>)
        ).toBe(true);
    });
});

redux의 공식 문서에서 제안하듯이 연결되지 않은 구성 요소도 내보내는 것이 좋습니다.

데코레이터를 처리하지 않고 App 컴포넌트 자체를 테스트할 수 있도록 꾸미지 않은 컴포넌트도 내보내는 것이 좋습니다.

import { connect } from 'react-redux'

// Use named export for unconnected component (for tests)
export class App extends Component { /* ... */ }
 
// Use default export for the connected component (for app)
export default connect(mapStateToProps)(App)

기본 내보내기는 여전히 장식된 컴포넌트이므로 위의 Import 스테이트먼트는 이전과 동일하게 작동하므로 응용 프로그램 코드를 변경할 필요가 없습니다.그러나 이제 테스트 파일에서 다음과 같이 꾸미지 않은 앱 구성 요소를 가져올 수 있습니다.

// Note the curly braces: grab the named export instead of default export
import { App } from './App'

둘 다 필요한 경우:

import ConnectedApp, { App } from './App'

앱 자체에서도 정상적으로 Import할 수 있습니다.

import App from './App'

명명된 내보내기는 테스트에만 사용합니다.

에 'Resact-redux'가 볼 수 .Provider store의 .

★★★Provider를 지정하면 컴포넌트가 .이것을 컴포넌트라고 .App애플리케이션 내의 다른 모든 컴포넌트를 렌더링하는 컴포넌트.

, 여기이 있어요. 이렇게 구성 요.connect(), 즉 "", ""connect()는 계층 중 " " "를 컴포넌트를 볼 수 있을 으로 예상합니다.Provider붙이다

, '를 붙이는 로 되어 있습니다.connect()됩니다.Provider.

이것이 당신이 원하는 것이지만, 당신의 테스트 환경에서는 그 흐름이 무너지고 있습니다.

왜요?

왜요?

가정된 sportsDatabase 테스트 파일로 돌아가면 사용자가 직접 sportsDatabase 컴포넌트가 되어 해당 컴포넌트를 단독으로 렌더링해야 합니다.

따라서 기본적으로 테스트 파일 내에서 수행하는 작업은 해당 구성 요소를 가져다가 야생에 버리는 것입니다. 이 구성 요소는 다른 구성 요소와는 아무런 관련이 없습니다.Provider또는 그 위에 저장하기 때문에 이 메시지가 나타납니다.

매장도 없고Provider그 컴포넌트의 컨텍스트 또는 프로포트에서 태그가 붙기 때문에 컴포넌트는 에러를 발생시킵니다.Provider태그를 지정하거나 상위 계층에 저장합니다.

그게 바로 그 오류의 의미입니다.

나로서는

const myReducers = combineReducers({
  user: UserReducer
});

const store: any = createStore(
  myReducers,
  applyMiddleware(thunk)
);

shallow(<Login />, { context: { store } });

저에게는 수입 문제였습니다만, 도움이 되었으면 합니다.WebStorm에 의한 디폴트 Import는 잘못된 것입니다.

교체하다

import connect from "react-redux/lib/connect/connect";

와 함께

import {connect} from "react-redux";

업그레이드 할 때 이런 일이 있었어요.다시 다운그레이드해야 했어요

react-backx ^5.0.6 → ^7.1.3

jus는 {shall, mount}을(를) "from "에서 Import합니다.

const store = mockStore({
  startup: { complete: false }
});

describe("==== Testing App ======", () => {
  const setUpFn = props => {
    return mount(
      <Provider store={store}>
        <App />
      </Provider>
    );
  };

  let wrapper;
  beforeEach(() => {
    wrapper = setUpFn();
  });

Index.js는 다음 코드를 추가해야 합니다.

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter  } from 'react-router-dom';

import './index.css';
import App from './App';

import { Provider } from 'react-redux';
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
import thunk from 'redux-thunk';

///its your redux ex
import productReducer from './redux/reducer/admin/product/produt.reducer.js'

const rootReducer = combineReducers({
    adminProduct: productReducer
   
})
const composeEnhancers = window._REDUX_DEVTOOLS_EXTENSION_COMPOSE_ || compose;
const store = createStore(rootReducer, composeEnhancers(applyMiddleware(thunk)));


const app = (
    <Provider store={store}>
        <BrowserRouter   basename='/'>
            <App />
        </BrowserRouter >
    </Provider>
);
ReactDOM.render(app, document.getElementById('root'));

이 문제의 원인이 되고 있는 라이브러리 메서드의 mock을 추가합니다.에는 그런 .useIsConnectedreact-native-offline을 사용하다

jest.mock("react-native-offline", () => ({ useIsConnected: jest.fn() }));

언급URL : https://stackoverflow.com/questions/36211739/invariant-violation-could-not-find-store-in-either-the-context-or-props-of-c