Pełny kod tutaj: https://gist.github.com/js08/0ec3d70dfda76d7e9fb4
Cześć,
- Mam aplikację, w której pokazuje różne szablony dla komputerów stacjonarnych i mobilnych w oparciu o środowisko kompilacji.
- Z powodzeniem mogę go opracować tam, gdzie muszę ukryć menu nawigacyjne dla mojego szablonu mobilnego.
- w tej chwili jestem w stanie napisać jeden przypadek testowy, w którym pobiera wszystkie wartości przez proptypes i renderuje się poprawnie
- ale nie jestem pewien, jak napisać jednostkowe przypadki testowe, gdy jego telefon komórkowy nie powinien renderować komponentu nawigacyjnego.
- Próbowałem, ale napotykam błąd ... czy możesz mi powiedzieć, jak to naprawić.
- Dowód kodu poniżej.
Przypadek testowy
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;
});
});
Fragment kodu, w którym należy zapisać przypadek testowy
if (sports.build === 'mobile') {
sportsNavigationComponent = <div />;
sportsSideMEnu = <div />;
searchComponent = <div />;
sportsPlayersWidget = <div />;
}
Błąd
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)
let SportsTopPortion = connect(mapStateToProps)(SomeOtherComponent)
. Najłatwiejszą odpowiedzią jest przetestowanie tego innego komponentu, a nie komponentu zwracanego przezconnect
.searchComponent = <SportsDatabase sportsWholeFramework="desktop" />;
. To jest połączony komponent, który oczekuje sklepu i się psuje. Tak więc dwie nowe sugestie: albo wykonaj tylko płytkie renderowanie SportsTopPane, albo użyj biblioteki takiej jak Enzyme do przetestowania. Zobacz airbnb.io/enzyme/docs/api/ReactWrapper/setContext.html .Możliwe rozwiązanie, które zadziałało dla mnie żartem
źródło
Jak oficjalna dokumentacja sugerują Redux, lepiej wyeksportować również niepołączony komponent.
Aby móc przetestować sam komponent aplikacji bez konieczności zajmowania się dekoratorem, zalecamy wyeksportowanie również niezdekorowanego komponentu:
Ponieważ domyślnym eksportem jest nadal dekorowany komponent, instrukcja importu przedstawiona powyżej będzie działać jak poprzednio, więc nie będziesz musiał zmieniać kodu aplikacji. Możesz jednak teraz importować niezdekorowane komponenty aplikacji do pliku testowego w następujący sposób:
A jeśli potrzebujesz obu:
W samej aplikacji nadal normalnie importujesz ją:
Nazwany eksport używałbyś tylko do testów.
źródło
Kiedy tworzymy aplikację react-redux, powinniśmy spodziewać się struktury, w której u góry mamy
Provider
tag, który zawiera instancję sklepu redux.Ten
Provider
tag następnie renderuje komponent nadrzędny, nazwijmy goApp
komponentem, który z kolei renderuje każdy inny komponent wewnątrz aplikacji.Oto kluczowa część, kiedy opakowujemy komponent
connect()
funkcją, taconnect()
funkcja oczekuje , że zobaczy jakiś komponent nadrzędny w hierarchii, która maProvider
znacznik.Więc instancja, w której umieścisz
connect()
funkcję, przeszuka hierarchię i spróbuje znaleźćProvider
.To jest to, co chcesz, aby się wydarzyło, ale w twoim środowisku testowym ten przepływ się psuje.
Czemu?
Czemu?
Kiedy wracamy do zakładanego pliku testowego sportsDatabase, musisz sam być komponentem sportsDatabase, a następnie próbować renderować ten komponent samodzielnie w izolacji.
Więc zasadniczo to, co robisz w tym pliku testowym, to po prostu pobranie tego komponentu i po prostu wyrzucenie go na wolność i nie ma on żadnych powiązań z żadnym
Provider
lub magazynem nad nim i dlatego widzisz tę wiadomość.W
Provider
kontekście lub właściwości tego komponentu nie ma magazynu ani tagu, więc komponent zgłasza błąd, ponieważ chce zobaczyćProvider
tag lub przechowywać w swojej nadrzędnej hierarchii.Więc to właśnie oznacza ten błąd.
źródło
w moim przypadku po prostu
shallow(<Login />, { context: { store } });
źródło
po prostu zrób to importuj {płytko, góra} z "enzymu";
źródło
Dla mnie był to problem z importem, mam nadzieję, że pomoże. domyślny import przez WebStorm był nieprawidłowy.
zastąpić
z
źródło
Zdarzyło mi się to, kiedy zaktualizowałem. Musiałem cofnąć się.
reag-reduks ^ 5,0,6 → ^ 7,1.3
źródło
na końcu pliku Index.js należy dodać ten kod:
źródło