return ({ startPath, steps }) => { const history = createHistory(startPath) const div = document.createElement('div') const { push } = history const next = function () { if (steps.length) steps.shift()({ html: div.innerHTML, push }) } const Container = React.createClass({ componentDidMount: next, componentDidUpdate: next, render() { return this.props.children } }) render(( <Router history={history} routes={<Route component={Container} children={routes}/>} render={props => ( <AsyncProps {...props} {...extraProps} renderLoading={() => <div>loading</div>} /> )} /> ), div, next) }
app.use((req, res) => { const memoryHistory = createHistory(req.originalUrl); const store = createStore(memoryHistory); const history = syncHistoryWithStore(memoryHistory, store); match({ history, routes: routes(store), location: req.originalUrl }, (err, redirectLocation, renderProps) => { // TODO: redirect if (redirectLocation) { res.redirect(301, redirectLocation.pathname + redirectLocation.search); } if (err) { return res.status(500).end('Internal server error'); } if (!renderProps) { return res.status(404).end('Not Found'); } const component = ( <Provider store={store} > <RouterContext {...renderProps} /> </Provider> ); const finalState = JSON.stringify(store.getState()); const html = renderToString(component); res.status(200).end(renderFullPage(html, finalState)); }); });
/** * An express middleware that is capabable of doing React server side rendering. */ function universalReactAppMiddleware(request, response) { if (process.env.DISABLE_SSR) { if (process.env.NODE_ENV === 'development') { console.log('==> 🐌 Handling react route without SSR'); // eslint-disable-line no-console } // SSR is disabled so we will just return an empty html page and will // rely on the client to populate the initial react application state. const html = render(); response.status(200).send(html); return; } const history = createMemoryHistory(request.originalUrl); // Server side handling of react-router. // Read more about this here: // https://github.com/reactjs/react-router/blob/master/docs/guides/ServerRendering.md match({ routes, history }, (error, redirectLocation, renderProps) => { if (error) { response.status(500).send(error.message); } else if (redirectLocation) { response.redirect(302, redirectLocation.pathname + redirectLocation.search); } else if (renderProps) { // You can check renderProps.components or renderProps.routes for // your "not found" component or route respectively, and send a 404 as // below, if you're using a catch-all route. const html = render({ rootElement: <RouterContext {...renderProps} /> }); response.status(200).send(html); } else { response.status(404).send('Not found'); } }); }
it('should transition to the correct route', () => { const router = ReactTestUtils.renderIntoDocument( <Router history={createMemoryHistory('/')}> <Route path="/" component={() => ( <LinkContainer to="/target"> <Component>Target</Component> </LinkContainer> )} /> <Route path="/target" component={() => <div className="target" />} /> </Router> ); const anchor = ReactTestUtils.findRenderedDOMComponentWithTag( router, 'A' ); ReactTestUtils.Simulate.click(anchor, { button: 0 }); const target = ReactTestUtils.findRenderedDOMComponentWithClass( router, 'target' ); expect(target).to.exist; });
export default function (request, response) { const { token, user_id } = request.cookies; const initialState = { auth: { token, userId: user_id, user: {} }, }; const location = createLocation(request.url); const memoryHistory = createHistory(request.originalUrl); const store = createStore(memoryHistory, initialState); const history = syncHistoryWithStore(memoryHistory, store); const routes = getRoutes(store); match({ history, routes, location }, (error, redirectLocation, routerState) => { if (error) { return response.status(500).end('Internal server error'); } if (!routerState) { return response.status(400).end('Not found'); } const promises = _.concat( fetchAll(routerState, store), postAll(routerState, store, request, response), ); Promise.all(promises) .then(() => render(response, store, routerState)) .catch((err) => { console.error(err); response.status(500).end('Something went wrong'); }); }); }
export function RenderView(path, model) { const history = createHistory(path); const result = { html: null, status: 404, redirect: null }; match( { history, routes: getRoutes(), location: path }, (error, redirectLocation, renderProps) => { if (redirectLocation) { result.redirect = redirectLocation.pathname + redirectLocation.search; } else if (error) { result.status = 500; } else if (renderProps) { // if this is the NotFoundRoute, then return a 404 const isNotFound = renderProps.routes.filter((route) => route.status === 404).length > 0; result.status = isNotFound ? 404 : 200; const store = configureStore(model); const component = ( <Provider store={store}> <RouterContext {...renderProps} /> </Provider> ); result.html = ReactDOM.renderToString(<Html component={component} store={store} />); } else { result.status = 404; } }); return result; }
it('should not add extra DOM nodes', () => { const router = ReactTestUtils.renderIntoDocument( <Router history={createMemoryHistory('/')}> <Route path="/" component={() => ( <LinkContainer to={{ pathname: '/foo', query: { bar: 'baz' } }} > <Component>Foo</Component> </LinkContainer> )} /> </Router> ); const container = ReactTestUtils.findRenderedComponentWithType( router, LinkContainer ); const component = ReactTestUtils.findRenderedComponentWithType( router, Component ); expect(ReactDOM.findDOMNode(container)) .to.equal(ReactDOM.findDOMNode(component)); });
it('should make the correct href', () => { const router = ReactTestUtils.renderIntoDocument( <Router history={createMemoryHistory('/')}> <Route path="/" component={() => ( <LinkContainer to={{ pathname: '/foo', query: { bar: 'baz' }, hash: '#the-hash' }} > <Component>Foo</Component> </LinkContainer> )} /> </Router> ); const anchor = ReactTestUtils.findRenderedDOMComponentWithTag( router, 'A' ); expect(anchor.getAttribute('href')).to.equal('/foo?bar=baz#the-hash'); });
app.use((req, res) => { if (__DEVELOPMENT__) { // Do not cache webpack stats: the script file would change since // hot module replacement is enabled in the development env webpackIsomorphicTools.refresh(); } const client = new ApiClient(req); const memoryHistory = createHistory(req.originalUrl); const store = createStore(memoryHistory, client); const history = syncHistoryWithStore(memoryHistory, store); const logic = new Logic({store}); const MyProvider = Provider; MyProvider.prototype.getChildContext = function getChildContext() { return {store, logic}; }; Object.assign(MyProvider.childContextTypes, {logic: React.PropTypes.object}); function hydrateOnClient() { res.send('<!doctype html>\n' + ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} store={store}/>)); } if (__DISABLE_SSR__) { hydrateOnClient(); return; } match({history, routes: getRoutes(store), location: req.originalUrl}, (error, redirectLocation, renderProps) => { if (redirectLocation) { res.redirect(redirectLocation.pathname + redirectLocation.search); } else if (error) { console.error('ROUTER ERROR:', pretty.render(error)); res.status(500); hydrateOnClient(); } else if (renderProps) { loadOnServer({...renderProps, store, helpers: {client}}).then(() => { const component = ( <MyProvider store={store} key="provider"> <MuiThemeProvider > <ReduxAsyncConnect {...renderProps} /> </MuiThemeProvider> </MyProvider> ); res.status(200); global.navigator = {userAgent: req.headers['user-agent']}; res.send('<!doctype html>\n' + ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} component={component} store={store}/>)); }); } else { res.status(404).send('Not found'); } }); });
it('should call user defined click handlers', () => { const onClick = sinon.spy(); const childOnClick = sinon.spy(); const router = ReactTestUtils.renderIntoDocument( <Router history={createMemoryHistory('/')}> <Route path="/" component={() => ( <LinkContainer to="/target" onClick={onClick}> <Component onClick={childOnClick}>Foo</Component> </LinkContainer> )} /> <Route path="/target" component={() => <div className="target" />} /> </Router> ); const anchor = ReactTestUtils.findRenderedDOMComponentWithTag( router, 'A' ); ReactTestUtils.Simulate.click(anchor, { button: 0 }); expect(onClick).to.have.been.calledOnce; expect(childOnClick).to.have.been.calledOnce; });
app.get('/*', (req, res) => { const memHistory = createHistory(req.originalUrl); const store = makeStore(memHistory); const history = syncHistoryWithStore(memHistory, store); const routes = createRoutes(store); match({ history, routes, location: req.originalUrl }, (err, redirectLocation, renderProps) => { if (redirectLocation) { res.redirect(redirectLocation.pathname + redirectLocation.search); } else if (err) { console.error('ROUTER ERROR:', error); res.status(500); } else if (renderProps) { loadOnServer({...renderProps, store}) .then(() => { // Check if there's a 404 after loading data on server if (store.getState().ssr.error404) { res.status(404); } var html; try { html = renderToString( <Provider store={store} key="provider"> <ReduxAsyncConnect {...renderProps} /> </Provider> ); } catch(e) { html = ''; } const head = Helmet.rewind(); const title = head.title.toString(); const meta = head.meta.toString(); const link = head.link.toString(); const chunks = parameters.chunks(); const appJs = chunks && chunks.javascript && chunks.javascript.main; const appCss = chunks && chunks.styles && chunks.styles.main; res.render('index', {html, title, meta, link, store, appCss, appJs}); }) .catch(err => { console.error(err.stack); res.status(500); if (__DEV__) { res.send(err.stack); } else { res.send('Server Error'); } }); } else { res.status(404).send('Not Found'); } }); });
app.use((req, res) => { if (__DEVELOPMENT__) { // Do not cache webpack stats: the script file would change since // hot module replacement is enabled in the development env webpackIsomorphicTools.refresh(); } const simpleIsoFetch = new SimpleIsoFetch(req); const memoryHistory = createHistory(req.originalUrl); // sends initial html to client function hydrateOnClient(initialState, component) { res.send(`<!doctype html> ${ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} store={initialState} {...(component && {component} || {})}/>)}`); } // check session to see if user is logged in, pass result into store as user object simpleIsoFetch.get('/session') .then(({body: user}) => handleRender(createStore(memoryHistory, simpleIsoFetch, { // initial state set here (with things that can only be retrieved server-side included) auth: {user}, navigator: {userAgent: req.headers['user-agent']} }))) .catch(err => console.log('session error', err)); function handleRender(store) { syncBindingsWithStore(simpleIsoFetch, store); // attach api response bindings to state const history = syncHistoryWithStore(memoryHistory, store); // attach routing to state if (__DISABLE_SSR__) { hydrateOnClient(store); return; } match({ history, routes: getRoutes(store), location: req.originalUrl }, (error, redirectLocation, renderProps) => { if (redirectLocation) { res.redirect(redirectLocation.pathname + redirectLocation.search); } else if (error) { console.error('ROUTER ERROR: ', pretty.render(error)); res.status(500); hydrateOnClient(store); } else if (renderProps) { loadOnServer({...renderProps, store, helpers: {client: simpleIsoFetch}}).then(() => { res.status(200); global.navigator = {userAgent: req.headers['user-agent']}; hydrateOnClient(store, ( <Provider store={store} key='provider'> <ReduxAsyncConnect {...renderProps} /> </Provider> )); }); } else { res.status(404).send('Not found'); } }); } });
render() { return ( <RelayRouter history={createMemoryHistory('/bar?queryName=baz')} routes={routes} onReadyStateChange={this.onReadyStateChange} /> ); }
const setup = routes => { const history = createMemoryHistory() const wrapper = mount( <Router history={ history }> { routes } </Router> ) return { history, wrapper } }
app.use((req, res) => { console.log('inside of the ssr') if (__DEVELOPMENT__) { // Do not cache webpack stats: the script file would change since // hot module replacement is enabled in the development env console.log("trying to refresh webpackisomorphic tools") webpackIsomorphicTools.refresh(); console.log("after webpackisomorphic tools refersh") } const client = new ApiClient(req); const memoryHistory = createHistory(req.originalUrl); const store = createStore(memoryHistory, client); const history = syncHistoryWithStore(memoryHistory, store); console.log('hello') function hydrateOnClient() { console.log('inside hydrateOnClient') res.send('<!doctype html>\n' + ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} store={store}/>)); } if (__DISABLE_SSR__) { hydrateOnClient(); return; } match({ history, routes: getRoutes(store), location: req.originalUrl }, (error, redirectLocation, renderProps) => { console.log('match callbakc') if (redirectLocation) { res.redirect(redirectLocation.pathname + redirectLocation.search); } else if (error) { console.error('ROUTER ERROR:', pretty.render(error)); res.status(500); hydrateOnClient(); } else if (renderProps) { loadOnServer({...renderProps, store, helpers: {client}}).then(() => { const component = ( <Provider store={store} key="provider"> <ReduxAsyncConnect {...renderProps} /> </Provider> ); res.status(200); global.navigator = {userAgent: req.headers['user-agent']}; res.send('meow') // // res.send('<!doctype html>\n' + // ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} component={component} store={store}/>)); }); } else { res.status(404).send('Not found'); } }); });
server.use((req, res, next) => { cookie.plugToRequest(req, res); const client = new ApiClient(req); const history = createHistory(req.originalUrl); const store = createStore(history, client); if (process.env.NODE_ENV === 'development') { webpack_isomorphic_tools.refresh() } if (req.query.DISABLE_SSR) { return res.status(200).send('<!doctype html>\n' + ReactDOM.renderToString( <Html store={store} assets={webpack_isomorphic_tools.assets()} /> )); } store.dispatch(setUserAgent(req.useragent)); store.dispatch(setOption(cookie.load('options') || {})); debug('Server', 'Executing navigate action'); match({ history, routes: routes(), location: req.originalUrl }, (error, redirectLocation, renderProps) => { debug('Server', 'Route match callback'); if (redirectLocation) { res.redirect(redirectLocation.pathname + redirectLocation.search); } else if (error) { console.error('ROUTER ERROR:', pretty.render(error)); res.status(500).send(error); } else if (renderProps) { loadOnServer({...renderProps, store, helpers: { client }}).then(() => { const component = ( <Provider store={store}> <ReduxAsyncConnect {...renderProps} /> </Provider> ); res.type('html'); res.setHeader('Cache-Control', 'public, max-age=31557600'); res.status(200); debug('Server', 'Sending markup'); res.send('<!doctype html>\n' + ReactDOM.renderToString( <Html component={component} store={store} assets={webpack_isomorphic_tools.assets()} /> )); }).catch(next); } }); });
app.use((req, res) => { if (__DEVELOPMENT__) { // Do not cache webpack stats: the script file would change since // hot module replacement is enabled in the development env webpackIsomorphicTools.refresh(); } const client = new ApiClient(req); const memoryHistory = createHistory(req.originalUrl); const i18nInstance = new I18n(); const data = { 'intl': { 'locale': i18nInstance.getLanguage().getCulture(), 'messages': i18nInstance.getCurrentLocalizedString()}}; const store = createStore(memoryHistory, client, data); const history = syncHistoryWithStore(memoryHistory, store); function hydrateOnClient() { res.send('<!doctype html>\n' + ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} store={store}/>)); } if (__DISABLE_SSR__) { hydrateOnClient(); return; } match({ history, routes: getRoutes(store), location: req.originalUrl }, (error, redirectLocation, renderProps) => { if (redirectLocation) { res.redirect(redirectLocation.pathname + redirectLocation.search); } else if (error) { console.error('ROUTER ERROR:', pretty.render(error)); res.status(500); hydrateOnClient(); } else if (renderProps) { loadOnServer({...renderProps, store, helpers: {client}}).then(() => { const component = ( <Provider store={store} key="provider"> <ReduxAsyncConnect {...renderProps} /> </Provider> ); res.status(200); global.navigator = {userAgent: req.headers['user-agent']}; res.send('<!doctype html>\n' + ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} component={component} store={store}/>)); }); } else { res.status(404).send('Not found'); } }); });
app.use((req, res) => { if (__DEVELOPMENT__) { // Do not cache webpack stats: the script file would change since // hot module replacement is enabled in the development env webpackIsomorphicTools.refresh() } const memoryHistory = createHistory(req.originalUrl) const store = createStore(memoryHistory) const history = syncHistoryWithStore(memoryHistory, store) function hydrateOnClient() { res.send('<!doctype html>\n' + ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} store={store} />)) } if (__DISABLE_SSR__) { hydrateOnClient() return } match({ history, routes: getRoutes(store), location: req.originalUrl }, (error, redirectLocation, renderProps) => { if (redirectLocation) { res.redirect(redirectLocation.pathname + redirectLocation.search) } else if (error) { console.error('ROUTER ERROR:', pretty.render(error)) res.status(500) hydrateOnClient() } else if (renderProps) { loadOnServer({...renderProps, store}).then(() => { const component = ( <Provider store={store} key="provider"> <ReduxAsyncConnect {...renderProps} /> </Provider> ) res.status(200) global.navigator = {userAgent: req.headers['user-agent']} res.send('<!doctype html>\n' + ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} component={component} store={store}/>)) }) } else { res.status(404).send('Not found') } }) })
export default function configureStore (initialState) { const middlewares = [thunk, dataloader, promise] if (__CLIENT__) { middlewares.push(syncHistory(browserHistory)) } else { middlewares.push(syncHistory(createMemoryHistory())) } if (__DEV__) { middlewares.push(createLogger()) } const finalCreateStore = applyMiddleware(...middlewares)(createStore) const store = finalCreateStore(rootReducer, initialState) return store }
return (req, res) => { if (__DEVELOPMENT__) { // Do not cache webpack stats: the script file would change since // hot module replacement is enabled in the development env isomorphicTools.refresh(); } const client = new ApiClient(req); const memoryHistory = createHistory(req.originalUrl); const store = createStore(memoryHistory, client); const history = syncHistoryWithStore(memoryHistory, store); if (config.DISABLE_SERVER_RENDERING) { return res.send(hydrateOnClient(store, isomorphicTools.assets())); } return match({ history, routes: getRoutes(store), location: req.originalUrl, }, (error, redirectLocation, renderProps) => { return parseMatchedRoute( error, redirectLocation, renderProps, client, store, isomorphicTools ).then((parsedRoute) => { const { status, payload, redirect, } = parsedRoute; if (redirect) { return res.redirect(redirect); } res.status(status); return res.send(payload); }).catch((err) => { console.error('error with route handler', err); }); }); };
app.use((req, res) => { if (__DEVELOPMENT__) { // Do not cache webpack stats: the script file would change since // hot module replacement is enabled in the development env webpackIsomorphicTools.refresh(); } const client = new ApiClient(req); const history = createHistory(req.originalUrl); const store = createStore(history, client); store.dispatch(setToken(req.cookies.user_token)); client.setStore(store); function hydrateOnClient() { res.send('<!doctype html>\n' + ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} store={store}/>)); } if (__DISABLE_SSR__) { hydrateOnClient(); return; } match({ history, routes: getRoutes(store, client), location: req.originalUrl }, (error, redirectLocation, renderProps, ...args) => { if (redirectLocation) { res.redirect(redirectLocation.pathname + redirectLocation.search); } else if (error) { console.error('ROUTER ERROR:', pretty.render(error)); res.status(500); hydrateOnClient(); } else if (renderProps) { loadOnServer({...renderProps, store, helpers: {client}}).then(() => { const component = rootComponent(store, <ReduxAsyncConnect {...renderProps} />); const status = getVal(renderProps, 'location.state.responseStatus', 200); res.status(status); global.navigator = {userAgent: req.headers['user-agent']}; res.send('<!doctype html>\n' + ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} component={component} store={store}/>)); }); } else { res.status(404).send('Not found'); } }); });
app.get('*', (req, res) => { const memoryHistory = createHistory(req.originalUrl); // Extract the accessToken from the cookies for authenticated API requests from the server. const token = req.cookies[TOKEN_COOKIES_KEY]; // undefined === the user is not logged in const instanceId = req.cookies[INSTANCEID_COOKIES_KEY] || null; // Selected instance const store = configureStore(memoryHistory, undefined, token, instanceId); const history = syncHistoryWithStore(memoryHistory, store); const location = req.originalUrl; match({ history, routes: createRoutes(store.getState), location }, (error, redirectLocation, renderProps) => { if (redirectLocation) { res.redirect(302, redirectLocation.pathname + redirectLocation.search); } else if (error) { // @todo use the 500.ejs view res.status(500).send(error.message); } else if (renderProps == null) { // this should never happen but just for sure - if router failed res.status(404).send('Not found'); } else { const userId = loggedInUserIdSelector(store.getState()); // try to get the user ID from the token (if any) const isSuperadmin = isLoggedAsSuperAdmin(store.getState()); const loadAsync = renderProps.components .filter(component => component) .map(component => { // there might be several layers of wrapping - connect, withLinks, ... while (component.WrappedComponent) { component = component.WrappedComponent; } return component; }) .filter(component => component.loadAsync) .map(component => component.loadAsync(renderProps.params, store.dispatch, { userId, isSuperadmin, instanceId, }) ); Promise.all(loadAsync) .then(() => renderPage(res, store, renderProps)) .catch(() => renderWithoutSSR(res, renderProps)); } }); });
export default function create(providedMiddleware, data, req) { // TODO: parameterize react-router let router; if (__CLIENT__) { router = syncHistory(useScroll(() => browserHistory)()); } else { router = syncHistory(createMemoryHistory()); } const defaultMiddleware = [ router ]; // backward compatibility to 2.x api expecting object for middleware instead of array: const customMiddleware = !providedMiddleware.concat ? map(providedMiddleware, (m) => { return m; }) : providedMiddleware; let middleware = customMiddleware.concat(defaultMiddleware); // if (__CLIENT__ && __LOGGER__) { // middleware.push(createLogger({ collapsed: true })); // } // Add express request as a 2nd argument to the middlewares if (__SERVER__) { middleware = middleware.map((fn) => function (obj) { return fn.call(this, obj, req); }); } const devtoolsExtensionMiddleware = () => __CLIENT__ && typeof window === 'object' && typeof window.devToolsExtension === 'function' ? window.devToolsExtension() : f => f // const useDevtools = __DEVELOPMENT__ && __CLIENT__ && __DEVTOOLS__; const finalCreateStore = compose( applyMiddleware(...middleware), devtoolsExtensionMiddleware() )(createStore) const store = finalCreateStore(reducers, data); hmr(store); return store; }
beforeEach(() => { router = ReactTestUtils.renderIntoDocument( <Router history={createMemoryHistory('/')}> <Route path="/" component={() => ( <LinkContainer to="/target" disabled> <Component>Target</Component> </LinkContainer> )} /> <Route path="/target" component={() => <div className="target" />} /> </Router> ); });
const setupTest = (routes = defaultRoutes) => { const history = createMemoryHistory() const store = configureStore(history) const tree = renderIntoDocument( <Provider store={store}> <Router history={history} > {routes} </Router> </Provider> ) return { history, store, tree } }
app.use((req, res, next) => { if (__DEVELOPMENT__) { webpackIsomorphicTools.refresh(); } const client = new ApiClient(req); const history = createHistory(req.originalUrl); const store = createStore(history, client); function hydrateOnClient() { res.send('<!doctype html>\n' + ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} store={store}/>)); } if (__DISABLE_SSR__) { hydrateOnClient(); return null; } match({ history, routes: getRoutes(store), location: req.originalUrl }, (error, redirectLocation, renderProps) => { if (redirectLocation) { res.redirect(redirectLocation.pathname + redirectLocation.search); } else if (error) { console.error('ROUTER ERROR:', pretty.render(error)); res.status(500); hydrateOnClient(); } else if (renderProps) { loadOnServer({...renderProps, store, helpers: {client}}).then(() => { const component = ( <Provider store={store} key="provider"> <ReduxAsyncConnect {...renderProps} /> </Provider> ); res.status(200); res.send('<!doctype html>\n' + ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} component={component} store={store}/>)); }); } else { res.status(404).send('Not found'); } }); });
const setupTest = (routes = defaultRoutes) => { const baseHistory = createMemoryHistory() const middleware = routerMiddleware(baseHistory) const initialState = Immutable.fromJS({ user: Immutable.fromJS({ authenticated: false, }), }) const store = createStore(rootReducer, initialState, applyMiddleware(middleware)) const history = syncHistoryWithStore(baseHistory, store, { selectLocationState: (state) => state.get('routing') }) const tree = renderIntoDocument( <Provider store={store}> <Router history={history}> {routes} </Router> </Provider> ) return { history, store, tree } }
function renderComponent(location) { const router = ReactTestUtils.renderIntoDocument( <Router history={createMemoryHistory(location)}> <Route path="/" component={() => ( <LinkContainer to="/foo"> <Component>Foo</Component> </LinkContainer> )} > <Route path="foo" /> <Route path="bar" /> </Route> </Router> ); const component = ReactTestUtils.findRenderedComponentWithType( router, Component ); return ReactDOM.findDOMNode(component); }
app.use((req, res) => { if (process.env.NODE_ENV === 'development') { webpackIsomorphicTools.refresh(); } const memoryHistory = createHistory(req.originalUrl); const store = createStore(memoryHistory); const history = syncHistoryWithStore(memoryHistory, store); function hydrateOnClient() { res.send(`<!doctype html>${ReactDOM.renderToString(<Default assets={webpackIsomorphicTools.assets()} store={store} />)}`); } match({ history, routes: getRoutes(store), location: req.originalUrl }, (error, redirectLocation, renderProps) => { if (redirectLocation) { res.redirect(redirectLocation.pathname + redirectLocation.search); } else if (error) { console.error('ROUTER ERROR:', pretty.render(error)); res.status(500); hydrateOnClient(); } else if (renderProps) { const component = ( <Provider store={store} key="provider"> <RouterContext {...renderProps} /> </Provider> ); res.status(200); global.navigator = { userAgent: req.headers['user-agent'] }; res.send(`<!doctype html>${ReactDOM.renderToStaticMarkup(<Default assets={webpackIsomorphicTools.assets()} component={component} store={store} />)}`); } else { res.status(404).send('Not found'); } }); });
const setupTest = (routes = defaultRoutes) => { const baseHistory = createMemoryHistory() const middleware = routerMiddleware(baseHistory) const store = createStore( rootReducer, applyMiddleware(middleware) ) const history = syncHistoryWithStore(baseHistory, store) const wrapper = mount( <Provider store={store}> <Router history={history} > {routes} </Router> </Provider> ) return { history, store, wrapper } }