Skip to content

Commit aba8410

Browse files
committed
Support passing store in via props for testing
1 parent d4ae7b4 commit aba8410

File tree

2 files changed

+40
-10
lines changed

2 files changed

+40
-10
lines changed

src/components/createConnect.js

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ export default function createConnect(React) {
3434
// Helps track hot reloading.
3535
const version = nextVersion++;
3636

37-
function computeStateProps(context) {
38-
const state = context.store.getState();
37+
function computeStateProps(store) {
38+
const state = store.getState();
3939
const stateProps = finalMapStateToProps(state);
4040
invariant(
4141
isPlainObject(stateProps),
@@ -45,8 +45,8 @@ export default function createConnect(React) {
4545
return stateProps;
4646
}
4747

48-
function computeDispatchProps(context) {
49-
const { dispatch } = context.store;
48+
function computeDispatchProps(store) {
49+
const { dispatch } = store;
5050
const dispatchProps = finalMapDispatchToProps(dispatch);
5151
invariant(
5252
isPlainObject(dispatchProps),
@@ -72,7 +72,7 @@ export default function createConnect(React) {
7272
static WrappedComponent = WrappedComponent;
7373

7474
static contextTypes = {
75-
store: storeShape.isRequired
75+
store: storeShape
7676
};
7777

7878
shouldComponentUpdate(nextProps, nextState) {
@@ -82,13 +82,17 @@ export default function createConnect(React) {
8282
constructor(props, context) {
8383
super(props, context);
8484
this.version = version;
85-
this.stateProps = computeStateProps(context);
86-
this.dispatchProps = computeDispatchProps(context);
85+
this.store = props.store || context.store;
86+
87+
invariant(this.store, '`store` must be passed in via the context or props');
88+
89+
this.stateProps = computeStateProps(this.store);
90+
this.dispatchProps = computeDispatchProps(this.store);
8791
this.state = this.computeNextState();
8892
}
8993

9094
recomputeStateProps() {
91-
const nextStateProps = computeStateProps(this.context);
95+
const nextStateProps = computeStateProps(this.store);
9296
if (shallowEqual(nextStateProps, this.stateProps)) {
9397
return false;
9498
}
@@ -98,7 +102,7 @@ export default function createConnect(React) {
98102
}
99103

100104
recomputeDispatchProps() {
101-
const nextDispatchProps = computeDispatchProps(this.context);
105+
const nextDispatchProps = computeDispatchProps(this.store);
102106
if (shallowEqual(nextDispatchProps, this.dispatchProps)) {
103107
return false;
104108
}
@@ -128,7 +132,7 @@ export default function createConnect(React) {
128132

129133
trySubscribe() {
130134
if (shouldSubscribe && !this.unsubscribe) {
131-
this.unsubscribe = this.context.store.subscribe(::this.handleChange);
135+
this.unsubscribe = this.store.subscribe(::this.handleChange);
132136
this.handleChange();
133137
}
134138
}

test/components/connect.spec.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,32 @@ describe('React', () => {
713713
expect(decorated.WrappedComponent).toBe(Container);
714714
});
715715

716+
it('should use the store from the props instead of from the context if present', () => {
717+
class Container extends Component {
718+
render() {
719+
return <div />;
720+
}
721+
}
722+
723+
let actualState;
724+
725+
const expectedState = { foos: {} };
726+
const decorator = connect(state => {
727+
actualState = state;
728+
return {};
729+
});
730+
const Decorated = decorator(Container);
731+
const mockStore = {
732+
dispatch: () => {},
733+
subscribe: () => {},
734+
getState: () => expectedState
735+
};
736+
737+
TestUtils.renderIntoDocument(<Decorated store={mockStore} />);
738+
739+
expect(actualState).toEqual(expectedState);
740+
});
741+
716742
it('should return the instance of the wrapped component for use in calling child methods', () => {
717743
const store = createStore(() => ({}));
718744

0 commit comments

Comments
 (0)