Code complet ici: https://Gist.github.com/js08/0ec3d70dfda76d7e9fb4
Salut,
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)
C'est assez simple. Vous essayez de tester le composant wrapper généré en appelant connect()(MyPlainComponent)
. Ce composant wrapper s'attend à avoir accès à un magasin Redux. Normalement, ce magasin est disponible sous la forme context.store
, car vous avez un <Provider store={myStore} />
au sommet de votre hiérarchie de composants. Cependant, vous effectuez le rendu de votre composant connecté lui-même, sans magasin, ce qui génère une erreur.
Vous avez quelques options:
<Provider>
autour de votre composant connecté<MyConnectedComponent store={store} />
, car le composant connecté acceptera également "magasin" comme accessoire.mapStateToProps
, vous pouvez supposer en toute sécurité que la version connectée fonctionnera correctement.Vous voudrez probablement lire la page "Test" dans la documentation Redux: https://redux.js.org/recipes/writing-tests .
éditer :
Après avoir constaté que vous avez posté la source et relu le message d'erreur, le vrai problème ne concerne pas le composant SportsTopPane. Le problème est que vous essayez de rendre "totalement" le rendu de SportsTopPane, qui restitue également tous ses enfants, plutôt que de faire un rendu "superficiel" comme dans le premier cas. La ligne searchComponent = <SportsDatabase sportsWholeFramework="desktop" />;
rend un composant qui, je suppose, est également connecté et s'attend donc à ce qu'un magasin soit disponible dans la fonction "contexte" de React.
À ce stade, vous avez deux nouvelles options:
Dans l’ensemble, j’aimerais noter que l’on essaie peut-être de faire trop dans ce seul élément. Vous voudrez peut-être envisager de le diviser en éléments plus petits avec moins de logique par composant.
Solution possible qui a fonctionné pour moi avec plaisanterie
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);
});
});
Comme le suggère le docs de redux, il est préférable d’exporter également le composant non connecté.
Afin de pouvoir tester le composant App lui-même sans avoir à traiter avec le décorateur, nous vous recommandons également d'exporter le composant non décoré:
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)
Étant donné que l'exportation par défaut est toujours le composant décoré, l'instruction d'importation illustrée ci-dessus fonctionnera comme auparavant afin que vous n'ayez pas à modifier votre code d'application. Cependant, vous pouvez maintenant importer les composants de l'application non décorés dans votre fichier de test de la manière suivante:
// Note the curly braces: grab the named export instead of default export
import { App } from './App'
Et si vous avez besoin des deux:
import ConnectedApp, { App } from './App'
Dans l'application elle-même, vous l'importeriez toujours normalement:
import App from './App'
Vous utiliseriez uniquement l'exportation nommée pour les tests.
Lorsque nous assemblons une application react-redux, nous devrions nous attendre à voir une structure dans laquelle se trouve en haut la balise Provider
qui contient une instance d'un magasin redux.
Cette balise Provider
restitue alors votre composant parent. Appelons-la le composant App
qui rend tous les autres composants de l'application.
Voici la partie clé, lorsque nous encapsulons un composant avec la fonction connect()
, cette fonction connect()
s'attend à voir un composant parent dans la hiérarchie ayant la balise Provider
.
Ainsi, si vous placez la fonction connect()
dans celle-ci, elle recherchera la hiérarchie et tentera de trouver la Provider
.
C’est ce que vous souhaitez, mais dans votre environnement de test, ce flux est en panne.
Pourquoi?
Pourquoi?
Lorsque nous revenons au fichier de test sportsDatabase supposé, vous devez être le composant sportsDatabase en lui-même, puis essayer de restituer ce composant seul.
Donc, ce que vous faites dans le fichier de test consiste essentiellement à prendre ce composant et à le jeter à l'état sauvage. Il n'a aucun lien avec aucune Provider
ni aucun magasin au-dessus de celui-ci et c'est pourquoi vous voyez ce message.
Il n'y a pas de marqueur ni de balise Provider
dans le contexte ou l'accessoire de ce composant; le composant renvoie donc une erreur car il souhaite voir une balise Provider
ou un magasin dans sa hiérarchie parent.
C’est donc ce que cette erreur signifie.
dans mon cas juste
const myReducers = combineReducers({
user: UserReducer
});
const store: any = createStore(
myReducers,
applyMiddleware(thunk)
);
shallow(<Login />, { context: { store } });