Skip to content

Commit

Permalink
Support renderPending with named routes
Browse files Browse the repository at this point in the history
  • Loading branch information
taion committed Sep 9, 2017
1 parent 4c7ea60 commit d16aa0c
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 24 deletions.
2 changes: 1 addition & 1 deletion src/utils/resolveRenderArgs.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default async function* resolveRenderArgs({
for await (const elements of resolver.resolveElements(augmentedMatch)) {
yield {
...augmentedMatch,
elements: foldElements([...elements], match.routeIndices),
elements: elements && foldElements([...elements], match.routeIndices),
};
}
} catch (e) {
Expand Down
25 changes: 25 additions & 0 deletions test/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import resolver from '../src/resolver';

export function timeout(delay) {
return new Promise((resolve) => {
setTimeout(resolve, delay);
});
}

export class InstrumentedResolver {
constructor() {
// This should be a rejected promise to prevent awaiting on done before
// trying to resolve, but Node doesn't like naked unresolved promises.
this.done = new Promise(() => {});
}

async * resolveElements(match) {
let resolveDone;
this.done = new Promise((resolve) => {
resolveDone = resolve;
});

yield* resolver.resolveElements(match);
resolveDone();
}
}
77 changes: 54 additions & 23 deletions test/render.test.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
import ServerProtocol from 'farce/lib/ServerProtocol';
import React from 'react';
import ReactTestUtils from 'react-dom/test-utils';

import createFarceRouter from '../src/createFarceRouter';
import createRender from '../src/createRender';
import getFarceResult from '../src/server/getFarceResult';

async function render(url, routeConfig) {
const { element } = await getFarceResult({
url,
routeConfig,
render: createRender({}),
});

return ReactTestUtils.renderIntoDocument(element);
}
import { timeout, InstrumentedResolver } from './helpers';

describe('render', () => {
it('should support nested routes', async () => {
const instance = await render(
'/foo/baz/a',
[
const Router = createFarceRouter({
historyProtocol: new ServerProtocol('/foo/baz/a'),
routeConfig: [
{
path: 'foo',
Component: ({ children }) => <div className="foo">{children}</div>,
getComponent: async () => {
await timeout(20);
return ({ children }) => <div className="foo">{children}</div>;
},
children: [
{
path: 'bar',
Expand All @@ -36,8 +32,24 @@ describe('render', () => {
],
},
],

render: createRender({
renderPending: () => <div className="pending" />,
}),
});

const resolver = new InstrumentedResolver();
const instance = ReactTestUtils.renderIntoDocument(
<Router resolver={resolver} />,
);

// Initial pending render is asynchronous.
await timeout(10);

ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'pending');

await resolver.done;

ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'foo');
expect(
ReactTestUtils.scryRenderedDOMComponentsWithClass(instance, 'bar'),
Expand All @@ -50,17 +62,20 @@ describe('render', () => {
});

it('should support named child routes', async () => {
const instance = await render(
'/foo/bar/qux/a',
[
const Router = createFarceRouter({
historyProtocol: new ServerProtocol('/foo/bar/qux/a'),
routeConfig: [
{
path: 'foo',
Component: ({ nav, main }) => (
<div className="foo">
{nav}
{main}
</div>
),
getComponent: async () => {
await timeout(20);
return ({ nav, main }) => (
<div className="foo">
{nav}
{main}
</div>
);
},
children: [
{
path: 'bar',
Expand Down Expand Up @@ -88,8 +103,24 @@ describe('render', () => {
],
},
],

render: createRender({
renderPending: () => <div className="pending" />,
}),
});

const resolver = new InstrumentedResolver();
const instance = ReactTestUtils.renderIntoDocument(
<Router resolver={resolver} />,
);

// Initial pending render is asynchronous.
await timeout(10);

ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'pending');

await resolver.done;

ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'foo');
ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'bar-nav');

Expand Down
105 changes: 105 additions & 0 deletions test/server/getFarceResult.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import React from 'react';
import ReactTestUtils from 'react-dom/test-utils';

import createRender from '../../src/createRender';
import getFarceResult from '../../src/server/getFarceResult';

async function render(url, routeConfig) {
const { element } = await getFarceResult({
url,
routeConfig,
render: createRender({}),
});

return ReactTestUtils.renderIntoDocument(element);
}

describe('getFarceResult', () => {
it('should support nested routes', async () => {
const instance = await render(
'/foo/baz/a',
[
{
path: 'foo',
Component: ({ children }) => <div className="foo">{children}</div>,
children: [
{
path: 'bar',
Component: () => <div className="bar" />,
},
{
path: 'baz/:qux',
Component: ({ params }) => (
<div className="baz">{params.qux}</div>
),
},
],
},
],
);

ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'foo');
expect(
ReactTestUtils.scryRenderedDOMComponentsWithClass(instance, 'bar'),
).toHaveLength(0);

const bazNode = ReactTestUtils.findRenderedDOMComponentWithClass(
instance, 'baz',
);
expect(bazNode.textContent).toBe('a');
});

it('should support named child routes', async () => {
const instance = await render(
'/foo/bar/qux/a',
[
{
path: 'foo',
Component: ({ nav, main }) => (
<div className="foo">
{nav}
{main}
</div>
),
children: [
{
path: 'bar',
children: {
nav: [
{
path: '(.*)?',
Component: () => <div className="bar-nav" />,
},
],
main: [
{
path: 'baz',
Component: () => <div className="baz" />,
},
{
path: 'qux/:quux',
Component: ({ params }) => (
<div className="qux">{params.quux}</div>
),
},
],
},
},
],
},
],
);

ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'foo');
ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'bar-nav');

expect(
ReactTestUtils.scryRenderedDOMComponentsWithClass(instance, 'baz'),
).toHaveLength(0);

const quxNode = ReactTestUtils.findRenderedDOMComponentWithClass(
instance, 'qux',
);
expect(quxNode.textContent).toBe('a');
});
});

0 comments on commit d16aa0c

Please sign in to comment.