rwr-redux 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.eslintrc +8 -0
- data/.rubocop.yml +4 -0
- data/CHANGELOG.md +16 -1
- data/README.md +80 -13
- data/Rakefile +21 -2
- data/docs/rails-redux-router.md +108 -0
- data/js/src/index.js +11 -98
- data/js/src/integrations/redux-container.js +69 -0
- data/js/src/integrations/redux-router.js +96 -0
- data/js/src/integrations/redux-store.js +50 -0
- data/js/src/version.js +1 -1
- data/js/test/helpers/redux-router.js +34 -0
- data/js/test/index.spec.js +19 -0
- data/js/test/integrations/redux-container.spec.js +163 -0
- data/js/test/integrations/redux-router.spec.js +147 -0
- data/js/test/integrations/redux-store.spec.js +105 -0
- data/lib/react_webpack_rails/redux_integration/services/redux_container.rb +27 -0
- data/lib/react_webpack_rails/redux_integration/services/redux_element.rb +33 -0
- data/lib/react_webpack_rails/redux_integration/services/redux_router.rb +27 -0
- data/lib/react_webpack_rails/redux_integration/version.rb +1 -1
- data/lib/react_webpack_rails/redux_integration/view_helpers.rb +39 -3
- data/package.json +21 -16
- data/redux_integration.gemspec +3 -2
- metadata +32 -5
- data/js/test/index.js +0 -188
@@ -0,0 +1,69 @@
|
|
1
|
+
import { createElement } from 'react';
|
2
|
+
import { Provider } from 'react-redux';
|
3
|
+
import { render, unmountComponentAtNode } from 'react-dom';
|
4
|
+
import { renderToString } from 'react-dom/server';
|
5
|
+
|
6
|
+
import ReduxStore from './redux-store';
|
7
|
+
|
8
|
+
class ReduxContainer {
|
9
|
+
constructor() {
|
10
|
+
this.containers = {};
|
11
|
+
|
12
|
+
this.registerContainer = this.registerContainer.bind(this);
|
13
|
+
}
|
14
|
+
|
15
|
+
registerContainer(name, container) {
|
16
|
+
this.containers[name] = container;
|
17
|
+
}
|
18
|
+
|
19
|
+
getContainer(name) {
|
20
|
+
return this.containers[name];
|
21
|
+
}
|
22
|
+
|
23
|
+
createContainer(name) {
|
24
|
+
const constructor = this.getContainer(name);
|
25
|
+
return createElement(constructor);
|
26
|
+
}
|
27
|
+
|
28
|
+
createRootComponent(name, storeName) {
|
29
|
+
const container = this.createContainer(name);
|
30
|
+
const store = ReduxStore.getStore(storeName);
|
31
|
+
|
32
|
+
return createElement(Provider, { store }, container);
|
33
|
+
}
|
34
|
+
|
35
|
+
renderContainer(name, node, storeName) {
|
36
|
+
const rootComponent = this.createRootComponent(name, storeName);
|
37
|
+
render(rootComponent, node);
|
38
|
+
}
|
39
|
+
|
40
|
+
unmountContainer(node) {
|
41
|
+
unmountComponentAtNode(node);
|
42
|
+
}
|
43
|
+
|
44
|
+
renderContainerToString(name, storeName) {
|
45
|
+
const rootComponent = this.createRootComponent(name, storeName);
|
46
|
+
const result = renderToString(rootComponent);
|
47
|
+
|
48
|
+
return JSON.stringify({ body: result });
|
49
|
+
}
|
50
|
+
|
51
|
+
get integrationWrapper() {
|
52
|
+
return {
|
53
|
+
mount: function _mount(node, payload) {
|
54
|
+
this.renderContainer(payload.name, node, payload.storeName);
|
55
|
+
}.bind(this),
|
56
|
+
|
57
|
+
unmount: function _unmount(node) {
|
58
|
+
this.unmountContainer(node);
|
59
|
+
}.bind(this),
|
60
|
+
|
61
|
+
nodeRun: function _prerender(payload) {
|
62
|
+
const { name, storeName } = payload;
|
63
|
+
return this.renderContainerToString(name, storeName);
|
64
|
+
}.bind(this),
|
65
|
+
};
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
export default new ReduxContainer;
|
@@ -0,0 +1,96 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { createElement } from 'react';
|
3
|
+
import { render, unmountComponentAtNode } from 'react-dom';
|
4
|
+
import { renderToString } from 'react-dom/server';
|
5
|
+
import { Provider } from 'react-redux';
|
6
|
+
import { Router, match, RouterContext, createMemoryHistory, browserHistory } from 'react-router';
|
7
|
+
import { syncHistoryWithStore } from 'react-router-redux';
|
8
|
+
|
9
|
+
import ReduxStore from './redux-store';
|
10
|
+
|
11
|
+
class ReduxRouter {
|
12
|
+
constructor() {
|
13
|
+
this.routes = {};
|
14
|
+
|
15
|
+
this.registerRoutes = this.registerRoutes.bind(this);
|
16
|
+
}
|
17
|
+
|
18
|
+
registerRoutes(name, routes) {
|
19
|
+
this.routes[name] = routes;
|
20
|
+
}
|
21
|
+
|
22
|
+
getRoutes(name) {
|
23
|
+
return this.routes[name];
|
24
|
+
}
|
25
|
+
|
26
|
+
createRootRouter(name, storeName) {
|
27
|
+
const routes = this.getRoutes(name);
|
28
|
+
const store = ReduxStore.getStore(storeName);
|
29
|
+
const history = syncHistoryWithStore(browserHistory, store);
|
30
|
+
|
31
|
+
return createElement(Provider, { store },
|
32
|
+
createElement(Router, { history }, routes)
|
33
|
+
);
|
34
|
+
}
|
35
|
+
|
36
|
+
unmountRouter(node) {
|
37
|
+
unmountComponentAtNode(node);
|
38
|
+
}
|
39
|
+
|
40
|
+
renderRouter(node, name, storeName) {
|
41
|
+
const rootRouter = this.createRootRouter(name, storeName);
|
42
|
+
render(rootRouter, node);
|
43
|
+
}
|
44
|
+
|
45
|
+
renderRouterToString(name, storeName, path) {
|
46
|
+
const routes = this.getRoutes(name);
|
47
|
+
const memoryHistory = createMemoryHistory(path);
|
48
|
+
const store = ReduxStore.getStore(storeName);
|
49
|
+
const history = syncHistoryWithStore(memoryHistory, store);
|
50
|
+
|
51
|
+
const result = {
|
52
|
+
body: '',
|
53
|
+
code: 0,
|
54
|
+
};
|
55
|
+
|
56
|
+
match({ history, routes, location: path }, (error, redirectLocation, renderProps) => {
|
57
|
+
if (error) {
|
58
|
+
throw error;
|
59
|
+
} else if (redirectLocation) {
|
60
|
+
result.code = 302;
|
61
|
+
result.redirectUri = `${redirectLocation.pathname}${redirectLocation.search}`;
|
62
|
+
} else if (renderProps) {
|
63
|
+
result.body = renderToString(
|
64
|
+
<Provider store={store}>
|
65
|
+
<RouterContext {...renderProps}/>
|
66
|
+
</Provider>
|
67
|
+
);
|
68
|
+
result.code = 200;
|
69
|
+
} else {
|
70
|
+
result.code = 404;
|
71
|
+
}
|
72
|
+
});
|
73
|
+
|
74
|
+
return JSON.stringify(result);
|
75
|
+
}
|
76
|
+
|
77
|
+
get integrationWrapper() {
|
78
|
+
return {
|
79
|
+
mount: function _mount(node, payload) {
|
80
|
+
const { name, storeName } = payload;
|
81
|
+
this.renderRouter(node, name, storeName);
|
82
|
+
}.bind(this),
|
83
|
+
|
84
|
+
unmount: function _unmount(node) {
|
85
|
+
this.unmountRouter(node);
|
86
|
+
}.bind(this),
|
87
|
+
|
88
|
+
nodeRun: function _nodeRun(payload) {
|
89
|
+
const { name, storeName, path } = payload;
|
90
|
+
return this.renderRouterToString(name, storeName, path);
|
91
|
+
}.bind(this),
|
92
|
+
};
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
export default new ReduxRouter;
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import { isFunction, isReduxStore } from '../utils/validators';
|
2
|
+
|
3
|
+
class ReduxStore {
|
4
|
+
constructor() {
|
5
|
+
this.registeredStores = {};
|
6
|
+
this.mountedStores = {};
|
7
|
+
this.defaultStore = null;
|
8
|
+
|
9
|
+
this.registerStore = this.registerStore.bind(this);
|
10
|
+
this.getStore = this.getStore.bind(this);
|
11
|
+
this.mountStore = this.mountStore.bind(this);
|
12
|
+
}
|
13
|
+
|
14
|
+
registerStore(name, store) {
|
15
|
+
isFunction(store, `Error when registering '${name}' store: must be a function.`);
|
16
|
+
this.registeredStores[name] = store;
|
17
|
+
}
|
18
|
+
|
19
|
+
mountStore(name, props) {
|
20
|
+
const store = this.registeredStores[name];
|
21
|
+
isFunction(store, `Error when mounting '${name}' store: must be a function.`);
|
22
|
+
|
23
|
+
const storeObject = store(props);
|
24
|
+
isReduxStore(storeObject, `Error when mounting '${name}' store: must be a valid Redux store.`);
|
25
|
+
this.mountedStores[name] = storeObject;
|
26
|
+
this.defaultStore = storeObject;
|
27
|
+
}
|
28
|
+
|
29
|
+
getStore(name) {
|
30
|
+
if (name) {
|
31
|
+
return this.mountedStores[name];
|
32
|
+
}
|
33
|
+
|
34
|
+
return this.defaultStore;
|
35
|
+
}
|
36
|
+
|
37
|
+
get integrationWrapper() {
|
38
|
+
return {
|
39
|
+
mount: function _mount(_, payload) {
|
40
|
+
this.mountStore(payload.name, payload.props);
|
41
|
+
}.bind(this),
|
42
|
+
|
43
|
+
nodeRun: function _mount(payload) {
|
44
|
+
this.mountStore(payload.name, payload.props);
|
45
|
+
}.bind(this),
|
46
|
+
};
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
export default new ReduxStore;
|
data/js/src/version.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export default '0.
|
1
|
+
export default '0.2.0';
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { createStore, combineReducers } from 'redux';
|
3
|
+
import { Route, Redirect } from 'react-router';
|
4
|
+
import { routerReducer } from 'react-router-redux';
|
5
|
+
|
6
|
+
import ReduxStore from '../../src/integrations/redux-store';
|
7
|
+
|
8
|
+
class AppComponent extends React.Component {
|
9
|
+
render() {
|
10
|
+
return <div>App Component</div>;
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
const routes = (
|
15
|
+
<Route path="/" component={AppComponent}>
|
16
|
+
<Redirect from="home" to="/" />
|
17
|
+
</Route>
|
18
|
+
);
|
19
|
+
|
20
|
+
const fakeReducer = combineReducers({ routing: routerReducer });
|
21
|
+
const store = function (initialState) {
|
22
|
+
return createStore(fakeReducer, initialState);
|
23
|
+
};
|
24
|
+
|
25
|
+
const registerRoutesAndMountStore = (subject) => {
|
26
|
+
subject.registerRoutes('RoutesName', routes);
|
27
|
+
ReduxStore.registerStore('StoreName', store);
|
28
|
+
ReduxStore.mountStore('StoreName', {});
|
29
|
+
};
|
30
|
+
|
31
|
+
export {
|
32
|
+
routes,
|
33
|
+
registerRoutesAndMountStore,
|
34
|
+
};
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import expect from 'expect';
|
2
|
+
import subject from '../src/index';
|
3
|
+
|
4
|
+
describe('RWRRedux', function () {
|
5
|
+
it('has correct properites', function () {
|
6
|
+
expect(subject.version).toBeA('string');
|
7
|
+
|
8
|
+
expect(subject.registerStore).toBeA('function');
|
9
|
+
expect(subject.mountStore).toBeA('function');
|
10
|
+
expect(subject.getStore).toBeA('function');
|
11
|
+
expect(subject.storeIntegrationWrapper).toBeA('object');
|
12
|
+
|
13
|
+
expect(subject.registerContainer).toBeA('function');
|
14
|
+
expect(subject.containerIntegrationWrapper).toBeA('object');
|
15
|
+
|
16
|
+
expect(subject.registerRoutes).toBeA('function');
|
17
|
+
expect(subject.routerIntegrationWrapper).toBeA('object');
|
18
|
+
});
|
19
|
+
});
|
@@ -0,0 +1,163 @@
|
|
1
|
+
import expect, { spyOn } from 'expect';
|
2
|
+
import { createStore } from 'redux';
|
3
|
+
import React from 'react';
|
4
|
+
import ReactDOM from 'react-dom';
|
5
|
+
import ReactDOMServer from 'react-dom/server';
|
6
|
+
|
7
|
+
import subject from '../../src/integrations/redux-container';
|
8
|
+
import ReduxStore from '../../src/integrations/redux-store';
|
9
|
+
|
10
|
+
class AppContainer extends React.Component {
|
11
|
+
render() {
|
12
|
+
return <div>AppContainer</div>;
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
const fakeReducer = function () {};
|
17
|
+
const store = function (initialState) {
|
18
|
+
return createStore(fakeReducer, initialState);
|
19
|
+
};
|
20
|
+
|
21
|
+
function resetConstructor() {
|
22
|
+
subject.containers = {};
|
23
|
+
expect.restoreSpies();
|
24
|
+
}
|
25
|
+
|
26
|
+
describe('ReduxContainer', function () {
|
27
|
+
before(function () {
|
28
|
+
resetConstructor();
|
29
|
+
});
|
30
|
+
|
31
|
+
afterEach(function () {
|
32
|
+
resetConstructor();
|
33
|
+
});
|
34
|
+
|
35
|
+
describe('.constructor', function () {
|
36
|
+
it('initialize empty containers object', function () {
|
37
|
+
expect(subject.containers).toEqual({});
|
38
|
+
});
|
39
|
+
});
|
40
|
+
|
41
|
+
describe('#registerContainer', function () {
|
42
|
+
it('adds container to the storage', function () {
|
43
|
+
subject.registerContainer('AppContainer', AppContainer);
|
44
|
+
|
45
|
+
expect(subject.containers.AppContainer).toEqual(AppContainer);
|
46
|
+
});
|
47
|
+
});
|
48
|
+
|
49
|
+
describe('#getContainer', function () {
|
50
|
+
it('returns container by name', function () {
|
51
|
+
subject.registerContainer('AppContainer', AppContainer);
|
52
|
+
|
53
|
+
expect(subject.getContainer('AppContainer')).toEqual(AppContainer);
|
54
|
+
});
|
55
|
+
});
|
56
|
+
|
57
|
+
describe('#createContainer', function () {
|
58
|
+
it('creates redux container', function () {
|
59
|
+
subject.registerContainer('AppContainer', AppContainer);
|
60
|
+
const container = subject.createContainer('AppContainer');
|
61
|
+
|
62
|
+
expect(React.isValidElement(container)).toBe(true);
|
63
|
+
expect(container.type).toBe(AppContainer);
|
64
|
+
});
|
65
|
+
});
|
66
|
+
|
67
|
+
describe('#createRootComponent', function () {
|
68
|
+
it('creates redux root component', function () {
|
69
|
+
const initialState = { fake: 'state' };
|
70
|
+
ReduxStore.registerStore('StoreName', store);
|
71
|
+
ReduxStore.mountStore('StoreName', initialState);
|
72
|
+
|
73
|
+
subject.registerContainer('AppContainer', AppContainer);
|
74
|
+
const rootComponent = subject.createRootComponent('AppContainer', 'ValidStore');
|
75
|
+
|
76
|
+
expect(React.isValidElement(rootComponent)).toBe(true);
|
77
|
+
});
|
78
|
+
});
|
79
|
+
|
80
|
+
describe('#renderContainer', function () {
|
81
|
+
it('calls #createRootComponent and ReactDOM.render functions', function () {
|
82
|
+
const subjectSpy = spyOn(subject, 'createRootComponent');
|
83
|
+
const reactSpy = spyOn(ReactDOM, 'render');
|
84
|
+
|
85
|
+
subject.renderContainer('ContainerName', 'node', 'StoreName');
|
86
|
+
|
87
|
+
expect(subjectSpy.calls.length).toEqual(1);
|
88
|
+
expect(subjectSpy).toHaveBeenCalledWith('ContainerName', 'StoreName');
|
89
|
+
expect(reactSpy.calls.length).toEqual(1);
|
90
|
+
});
|
91
|
+
});
|
92
|
+
|
93
|
+
describe('#unmountContainer', function () {
|
94
|
+
it('calls #unmountComponentAtNode', function () {
|
95
|
+
const node = { nodeType: 1, nodeName: 'DIV' };
|
96
|
+
const unmountSpy = spyOn(ReactDOM, 'unmountComponentAtNode');
|
97
|
+
|
98
|
+
subject.unmountContainer(node);
|
99
|
+
|
100
|
+
expect(unmountSpy.calls.length).toEqual(1);
|
101
|
+
expect(unmountSpy).toHaveBeenCalledWith(node);
|
102
|
+
});
|
103
|
+
});
|
104
|
+
|
105
|
+
describe('#renderContainerToString', function () {
|
106
|
+
it('calls #createRootComponent and ReactDOM.renderToString', function () {
|
107
|
+
const subjectSpy = spyOn(subject, 'createRootComponent');
|
108
|
+
const reactSpy = spyOn(ReactDOMServer, 'renderToString');
|
109
|
+
|
110
|
+
subject.renderContainerToString('ContainerName', 'StoreName');
|
111
|
+
|
112
|
+
expect(subjectSpy.calls.length).toEqual(1);
|
113
|
+
expect(subjectSpy).toHaveBeenCalledWith('ContainerName', 'StoreName');
|
114
|
+
expect(reactSpy.calls.length).toEqual(1);
|
115
|
+
});
|
116
|
+
|
117
|
+
it('returns JSON.stringify result', function () {
|
118
|
+
const initialState = { fake: 'state' };
|
119
|
+
ReduxStore.registerStore('StoreName', store);
|
120
|
+
ReduxStore.mountStore('StoreName', initialState);
|
121
|
+
subject.registerContainer('AppContainer', AppContainer);
|
122
|
+
|
123
|
+
const result = subject.renderContainerToString('AppContainer', 'StoreName');
|
124
|
+
|
125
|
+
expect(JSON.parse(result).body).toNotEqual(null);
|
126
|
+
});
|
127
|
+
});
|
128
|
+
|
129
|
+
describe('#integrationWrapper', function () {
|
130
|
+
const node = { nodeType: 1, nodeName: 'DIV' };
|
131
|
+
const payload = { name: 'ContainerName', storeName: 'StoreName' };
|
132
|
+
|
133
|
+
describe('mount', function () {
|
134
|
+
it('calls #renderContainer', function () {
|
135
|
+
const mountSpy = spyOn(subject, 'renderContainer');
|
136
|
+
subject.integrationWrapper.mount(node, payload);
|
137
|
+
|
138
|
+
expect(mountSpy.calls.length).toEqual(1);
|
139
|
+
expect(mountSpy).toHaveBeenCalledWith(payload.name, node, payload.storeName);
|
140
|
+
});
|
141
|
+
});
|
142
|
+
|
143
|
+
describe('unmount', function () {
|
144
|
+
it('calls #unmountContainer', function () {
|
145
|
+
const unmountSpy = spyOn(subject, 'unmountContainer');
|
146
|
+
subject.integrationWrapper.unmount(node);
|
147
|
+
|
148
|
+
expect(unmountSpy.calls.length).toEqual(1);
|
149
|
+
expect(unmountSpy).toHaveBeenCalledWith(node);
|
150
|
+
});
|
151
|
+
});
|
152
|
+
|
153
|
+
describe('nodeRun', function () {
|
154
|
+
it('calls #renderContainerToString', function () {
|
155
|
+
const nodeRunSpy = spyOn(subject, 'renderContainerToString');
|
156
|
+
subject.integrationWrapper.nodeRun(payload);
|
157
|
+
|
158
|
+
expect(nodeRunSpy.calls.length).toEqual(1);
|
159
|
+
expect(nodeRunSpy).toHaveBeenCalledWith(payload.name, payload.storeName);
|
160
|
+
});
|
161
|
+
});
|
162
|
+
});
|
163
|
+
});
|
@@ -0,0 +1,147 @@
|
|
1
|
+
import expect, { spyOn } from 'expect';
|
2
|
+
import ReactDOM from 'react-dom';
|
3
|
+
|
4
|
+
import subject from '../../src/integrations/redux-router';
|
5
|
+
import { routes, registerRoutesAndMountStore } from '../helpers/redux-router';
|
6
|
+
|
7
|
+
function resetConstructor() {
|
8
|
+
subject.routes = {};
|
9
|
+
expect.restoreSpies();
|
10
|
+
}
|
11
|
+
|
12
|
+
describe('ReduxRouter', function () {
|
13
|
+
before(function () {
|
14
|
+
resetConstructor();
|
15
|
+
});
|
16
|
+
|
17
|
+
afterEach(function () {
|
18
|
+
resetConstructor();
|
19
|
+
});
|
20
|
+
|
21
|
+
describe('.constructor', function () {
|
22
|
+
it('initialize empty routes object', function () {
|
23
|
+
expect(subject.routes).toEqual({});
|
24
|
+
});
|
25
|
+
});
|
26
|
+
|
27
|
+
describe('#registerRoutes', function () {
|
28
|
+
it('adds routes to the storage', function () {
|
29
|
+
subject.registerRoutes('RoutesName', routes);
|
30
|
+
|
31
|
+
expect(subject.routes.RoutesName).toEqual(routes);
|
32
|
+
});
|
33
|
+
});
|
34
|
+
|
35
|
+
describe('#getRoutes', function () {
|
36
|
+
it('returns routes by name', function () {
|
37
|
+
subject.registerRoutes('RoutesName', routes);
|
38
|
+
|
39
|
+
expect(subject.getRoutes('RoutesName')).toEqual(routes);
|
40
|
+
});
|
41
|
+
});
|
42
|
+
|
43
|
+
describe('#unmountRouter', function () {
|
44
|
+
it('calls #unmountComponentAtNode', function () {
|
45
|
+
const node = { nodeType: 1, nodeName: 'DIV' };
|
46
|
+
const unmountSpy = spyOn(ReactDOM, 'unmountComponentAtNode');
|
47
|
+
|
48
|
+
subject.unmountRouter(node);
|
49
|
+
|
50
|
+
expect(unmountSpy.calls.length).toEqual(1);
|
51
|
+
expect(unmountSpy).toHaveBeenCalledWith(node);
|
52
|
+
});
|
53
|
+
});
|
54
|
+
|
55
|
+
describe('#renderRouter', function () {
|
56
|
+
it('calls createRootRouter and render functions', function () {
|
57
|
+
const subjectSpy = spyOn(subject, 'createRootRouter').andReturn('router');
|
58
|
+
const reactSpy = spyOn(ReactDOM, 'render');
|
59
|
+
|
60
|
+
subject.renderRouter('node', 'RouterName', 'StoreName');
|
61
|
+
|
62
|
+
expect(subjectSpy.calls.length).toEqual(1);
|
63
|
+
expect(subjectSpy).toHaveBeenCalledWith('RouterName', 'StoreName');
|
64
|
+
expect(reactSpy.calls.length).toEqual(1);
|
65
|
+
expect(reactSpy).toHaveBeenCalledWith('router', 'node');
|
66
|
+
});
|
67
|
+
});
|
68
|
+
|
69
|
+
describe('#renderRouterToString', function () {
|
70
|
+
const renderRouterToString = (path) => {
|
71
|
+
const result = subject.renderRouterToString('RoutesName', 'StoreName', path);
|
72
|
+
return JSON.parse(result);
|
73
|
+
};
|
74
|
+
|
75
|
+
beforeEach(function () {
|
76
|
+
registerRoutesAndMountStore(subject);
|
77
|
+
});
|
78
|
+
|
79
|
+
context('when router can match location', function () {
|
80
|
+
it('returns string component and 200 status code', function () {
|
81
|
+
const validPath = '/';
|
82
|
+
const result = renderRouterToString(validPath);
|
83
|
+
|
84
|
+
expect(result.code).toEqual(200);
|
85
|
+
expect(result.body).toInclude('App Component');
|
86
|
+
});
|
87
|
+
});
|
88
|
+
|
89
|
+
context('when router returns redirectLocation', function () {
|
90
|
+
it('returns 302 status code and redirectUri', function () {
|
91
|
+
const redirectPath = '/home';
|
92
|
+
const result = renderRouterToString(redirectPath);
|
93
|
+
|
94
|
+
expect(result.code).toEqual(302);
|
95
|
+
expect(result.body).toEqual('');
|
96
|
+
expect(result.redirectUri).toEqual('/');
|
97
|
+
});
|
98
|
+
});
|
99
|
+
|
100
|
+
context('when router can not match location', function () {
|
101
|
+
it('returns 404 status code', function () {
|
102
|
+
const invalidPath = '/path';
|
103
|
+
const result = renderRouterToString(invalidPath);
|
104
|
+
|
105
|
+
expect(result.code).toEqual(404);
|
106
|
+
expect(result.body).toEqual('');
|
107
|
+
});
|
108
|
+
});
|
109
|
+
});
|
110
|
+
|
111
|
+
describe('#integrationWrapper', function () {
|
112
|
+
const node = { nodeType: 1, nodeName: 'DIV' };
|
113
|
+
const payload = { name: 'RouterName', storeName: 'StoreName', path: '/path' };
|
114
|
+
|
115
|
+
describe('#mount', function () {
|
116
|
+
it('calls #renderRouter', function () {
|
117
|
+
const { name, storeName } = payload;
|
118
|
+
const mountSpy = spyOn(subject, 'renderRouter');
|
119
|
+
subject.integrationWrapper.mount(node, payload);
|
120
|
+
|
121
|
+
expect(mountSpy.calls.length).toEqual(1);
|
122
|
+
expect(mountSpy).toHaveBeenCalledWith(node, name, storeName);
|
123
|
+
});
|
124
|
+
});
|
125
|
+
|
126
|
+
describe('#unmount', function () {
|
127
|
+
it('calls #unmountRouter', function () {
|
128
|
+
const unmountSpy = spyOn(subject, 'unmountRouter');
|
129
|
+
subject.integrationWrapper.unmount(node);
|
130
|
+
|
131
|
+
expect(unmountSpy.calls.length).toEqual(1);
|
132
|
+
expect(unmountSpy).toHaveBeenCalledWith(node);
|
133
|
+
});
|
134
|
+
});
|
135
|
+
|
136
|
+
describe('#nodeRun', function () {
|
137
|
+
it('calls #renderRouterToString', function () {
|
138
|
+
const { name, storeName, path } = payload;
|
139
|
+
const nodeRunSpy = spyOn(subject, 'renderRouterToString');
|
140
|
+
subject.integrationWrapper.nodeRun(payload);
|
141
|
+
|
142
|
+
expect(nodeRunSpy.calls.length).toEqual(1);
|
143
|
+
expect(nodeRunSpy).toHaveBeenCalledWith(name, storeName, path);
|
144
|
+
});
|
145
|
+
});
|
146
|
+
});
|
147
|
+
});
|