rwr-redux 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
});
|