Skip to content

Commit 86298c3

Browse files
committed
feat(custom-render): called a custom renderer when provided
1 parent 345b4c8 commit 86298c3

File tree

2 files changed

+29
-22
lines changed

2 files changed

+29
-22
lines changed

src/router-wrapper.js

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import React from 'react';
2-
import {renderToString} from 'react-dom/server';
3-
import {RouterContext} from 'react-router';
41
import Boom from 'boom';
52
import {MOVED_PERMANENTLY, MOVED_TEMPORARILY} from 'http-status-codes';
63
import matchRoute from './route-matcher';
74
import fetchData from './data-fetcher';
5+
import defaultRenderFactory from './default-render-factory';
86

9-
export default async function renderThroughReactRouter(request, h, {routes, respond, Root, store}) {
7+
export default async function renderThroughReactRouter(request, h, {render, routes, respond, Root, store}) {
108
try {
119
const {renderProps, status, redirectLocation} = await matchRoute(request.raw.req.url, routes);
1210

@@ -24,16 +22,12 @@ export default async function renderThroughReactRouter(request, h, {routes, resp
2422
} else {
2523
await fetchData({renderProps, store});
2624

25+
const defaultRender = defaultRenderFactory(request, store, renderProps, Root);
26+
2727
return respond(h, {
2828
store,
2929
status,
30-
renderedContent: {
31-
html: renderToString((
32-
<Root request={request} store={store}>
33-
<RouterContext {...renderProps} />
34-
</Root>
35-
))
36-
}
30+
renderedContent: render ? render(defaultRender) : {html: defaultRender()}
3731
});
3832
}
3933
} catch (e) {

test/unit/router-wrapper-test.js

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import React from 'react';
2-
import {RouterContext} from 'react-router';
3-
import domServer from 'react-dom/server';
4-
import {MOVED_TEMPORARILY, MOVED_PERMANENTLY} from 'http-status-codes';
1+
import {MOVED_PERMANENTLY, MOVED_TEMPORARILY} from 'http-status-codes';
52
import sinon from 'sinon';
63
import {assert} from 'chai';
74
import any from '@travi/any';
85
import Boom from 'boom';
96
import renderThroughReactRouter from '../../src/router-wrapper';
7+
import * as defaultRenderFactory from '../../src/default-render-factory';
108
import * as routeMatcher from '../../src/route-matcher';
119
import * as dataFetcher from '../../src/data-fetcher';
1210

@@ -25,8 +23,7 @@ suite('router-wrapper', () => {
2523
sandbox.stub(routeMatcher, 'default');
2624
sandbox.stub(dataFetcher, 'default');
2725
sandbox.stub(Boom, 'wrap');
28-
sandbox.stub(React, 'createElement');
29-
sandbox.stub(domServer, 'renderToString');
26+
sandbox.stub(defaultRenderFactory, 'default');
3027
});
3128

3229
teardown(() => sandbox.restore());
@@ -36,20 +33,36 @@ suite('router-wrapper', () => {
3633
const reply = sinon.spy();
3734
const renderProps = any.simpleObject();
3835
const status = any.integer();
39-
const context = any.simpleObject();
40-
const rootComponent = any.simpleObject();
4136
const html = any.string();
4237
const response = any.string();
38+
const defaultRender = sinon.stub();
4339
routeMatcher.default.withArgs(url, routes).resolves({renderProps, status});
4440
dataFetcher.default.withArgs({renderProps, store, status}).resolves({renderProps, status});
45-
React.createElement.withArgs(RouterContext, sinon.match(renderProps)).returns(context);
46-
React.createElement.withArgs(Root, {request, store}).returns(rootComponent);
47-
domServer.renderToString.withArgs(rootComponent).returns(html);
41+
defaultRender.returns(html);
42+
defaultRenderFactory.default.withArgs(request, store, renderProps, Root).returns(defaultRender);
4843
respond.withArgs(reply, {renderedContent: {html}, store, status}).returns(response);
4944

5045
return assert.becomes(renderThroughReactRouter(request, reply, {routes, respond, Root, store}), response);
5146
});
5247

48+
test('that response contains the custom-rendered content when a custom renderer is provided', async () => {
49+
const respond = sinon.stub();
50+
const reply = sinon.spy();
51+
const renderProps = any.simpleObject();
52+
const status = any.integer();
53+
const response = any.string();
54+
const render = sinon.stub();
55+
const renderedContent = any.simpleObject();
56+
const defaultRender = () => undefined;
57+
routeMatcher.default.withArgs(url, routes).resolves({renderProps, status});
58+
dataFetcher.default.withArgs({renderProps, store, status}).resolves({renderProps, status});
59+
respond.withArgs(reply, {renderedContent, store, status}).returns(response);
60+
defaultRenderFactory.default.withArgs(request, store, renderProps, Root).returns(defaultRender);
61+
render.withArgs(defaultRender).returns(renderedContent);
62+
63+
assert.equal(await renderThroughReactRouter(request, reply, {render, routes, respond, Root, store}), response);
64+
});
65+
5366
test('that a temporary redirect results when a redirectLocation is defined with a 302 status', () => {
5467
const respond = sinon.stub();
5568
const redirect = sinon.stub();

0 commit comments

Comments
 (0)