Skip to content

Commit 2dab29d

Browse files
committed
Adds support for nested routes
1 parent 9d783d9 commit 2dab29d

File tree

3 files changed

+57
-29
lines changed

3 files changed

+57
-29
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-router-breadcrumbs-hoc",
3-
"version": "2.0.0",
3+
"version": "2.0.1",
44
"description": "Just a tiny, flexible, higher order component for rendering breadcrumbs with react-router 4.x",
55
"repository": "icd2k3/react-router-breadcrumbs-hoc",
66
"keywords": [

src/index.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,20 @@ export const getBreadcrumbs = ({ routes, location, options = {} }) => {
120120
return matches;
121121
};
122122

123+
// takes a route array and recursively flattens it IF there are
124+
// nested routes in the config
125+
const flattenRoutes = routes => routes.reduce((arr, route) => {
126+
if (route.routes) {
127+
return arr.concat([route, ...flattenRoutes(route.routes)]);
128+
}
129+
return arr.concat(route);
130+
}, []);
131+
123132
const withBreadcrumbs = (routes = [], options) => Component => withRouter(props =>
124133
createElement(Component, {
125134
...props,
126135
breadcrumbs: getBreadcrumbs({
127-
routes,
136+
routes: flattenRoutes(routes),
128137
location: props.location,
129138
options,
130139
}),

src/index.test.js

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const render = ({
3838
mount(<Router initialIndex={0} initialEntries={[{ pathname, state }]}><Breadcrumbs /></Router>);
3939

4040
return {
41-
Breadcrumbs: wrapper.find('.breadcrumbs-container'),
41+
breadcrumbs: wrapper.find('.breadcrumbs-container').text(),
4242
wrapper,
4343
};
4444
};
@@ -87,8 +87,8 @@ describe('react-router-breadcrumbs-hoc', () => {
8787
// test a no-match route
8888
{ path: '/no-match', breadcrumb: 'no match' },
8989
];
90-
const { Breadcrumbs, wrapper } = render({ pathname: '/1/2/3/4', routes });
91-
expect(Breadcrumbs.text()).toBe('Home / One / TWO / 3 / Link');
90+
const { breadcrumbs, wrapper } = render({ pathname: '/1/2/3/4', routes });
91+
expect(breadcrumbs).toBe('Home / One / TWO / 3 / Link');
9292
expect(wrapper.find(NavLink).props().to).toBe('/1/2/3/4');
9393
});
9494
});
@@ -105,8 +105,8 @@ describe('react-router-breadcrumbs-hoc', () => {
105105
breadcrumb: '1',
106106
},
107107
];
108-
const { Breadcrumbs } = render({ pathname: '/user/create', routes });
109-
expect(Breadcrumbs.text()).toBe('Home / User / Add User');
108+
const { breadcrumbs } = render({ pathname: '/user/create', routes });
109+
expect(breadcrumbs).toBe('Home / User / Add User');
110110
});
111111

112112
it('Should match the first breadcrumb in route array user/:id', () => {
@@ -120,8 +120,8 @@ describe('react-router-breadcrumbs-hoc', () => {
120120
breadcrumb: 'Add User',
121121
},
122122
];
123-
const { Breadcrumbs } = render({ pathname: '/user/create', routes });
124-
expect(Breadcrumbs.text()).toBe('Home / User / Oops');
123+
const { breadcrumbs } = render({ pathname: '/user/create', routes });
124+
expect(breadcrumbs).toBe('Home / User / Oops');
125125
});
126126
});
127127

@@ -135,8 +135,8 @@ describe('react-router-breadcrumbs-hoc', () => {
135135
matchOptions: { exact: false, strict: true },
136136
},
137137
];
138-
const { Breadcrumbs } = render({ pathname: '/one', routes });
139-
expect(Breadcrumbs.text()).toBe('');
138+
const { breadcrumbs } = render({ pathname: '/one', routes });
139+
expect(breadcrumbs).toBe('');
140140
});
141141
});
142142

@@ -146,73 +146,92 @@ describe('react-router-breadcrumbs-hoc', () => {
146146
{ path: '/one', breadcrumb: 'OneCustom' },
147147
{ path: '/one/two' },
148148
];
149-
const { Breadcrumbs } = render({ pathname: '/one/two', routes });
150-
expect(Breadcrumbs.text()).toBe('Home / OneCustom / Two');
149+
const { breadcrumbs } = render({ pathname: '/one/two', routes });
150+
expect(breadcrumbs).toBe('Home / OneCustom / Two');
151+
});
152+
153+
it('Should support nested routes', () => {
154+
const routes = [
155+
{
156+
path: '/one',
157+
routes: [
158+
{
159+
path: '/one/two',
160+
breadcrumb: 'TwoCustom',
161+
routes: [
162+
{ path: '/one/two/three', breadcrumb: 'ThreeCustom' },
163+
],
164+
},
165+
],
166+
},
167+
];
168+
const { breadcrumbs } = render({ pathname: '/one/two/three', routes });
169+
expect(breadcrumbs).toBe('Home / One / TwoCustom / ThreeCustom');
151170
});
152171
});
153172

154173
describe('Defaults', () => {
155174
describe('No routes array', () => {
156175
it('Should automatically render breadcrumbs with default strings', () => {
157-
const { Breadcrumbs } = render({ pathname: '/one/two' });
176+
const { breadcrumbs } = render({ pathname: '/one/two' });
158177

159-
expect(Breadcrumbs.text()).toBe('Home / One / Two');
178+
expect(breadcrumbs).toBe('Home / One / Two');
160179
});
161180
});
162181

163182
describe('Override defaults', () => {
164183
it('Should render user-provided breadcrumbs where possible and use defaults otherwise', () => {
165184
const routes = [{ path: '/one', breadcrumb: 'Override' }];
166-
const { Breadcrumbs } = render({ pathname: '/one/two', routes });
185+
const { breadcrumbs } = render({ pathname: '/one/two', routes });
167186

168-
expect(Breadcrumbs.text()).toBe('Home / Override / Two');
187+
expect(breadcrumbs).toBe('Home / Override / Two');
169188
});
170189
});
171190

172191
describe('No breadcrumb', () => {
173192
it('Should be possible to NOT render a breadcrumb', () => {
174193
const routes = [{ path: '/one', breadcrumb: null }];
175-
const { Breadcrumbs } = render({ pathname: '/one/two', routes });
194+
const { breadcrumbs } = render({ pathname: '/one/two', routes });
176195

177-
expect(Breadcrumbs.text()).toBe('Home / Two');
196+
expect(breadcrumbs).toBe('Home / Two');
178197
});
179198

180199
it('Should be possible to NOT render a "Home" breadcrumb', () => {
181200
const routes = [{ path: '/', breadcrumb: null }];
182-
const { Breadcrumbs } = render({ pathname: '/one/two', routes });
201+
const { breadcrumbs } = render({ pathname: '/one/two', routes });
183202

184-
expect(Breadcrumbs.text()).toBe('One / Two');
203+
expect(breadcrumbs).toBe('One / Two');
185204
});
186205
});
187206
});
188207

189208
describe('When using the location object', () => {
190209
it('Should be provided in the rendered breadcrumb component', () => {
191210
const routes = [{ path: '/one', breadcrumb: components.BreadcrumbLocationTest }];
192-
const { Breadcrumbs } = render({ pathname: '/one', state: { isLocationTest: true }, routes });
193-
expect(Breadcrumbs.text()).toBe('Home / pass');
211+
const { breadcrumbs } = render({ pathname: '/one', state: { isLocationTest: true }, routes });
212+
expect(breadcrumbs).toBe('Home / pass');
194213
});
195214
});
196215

197216
describe('When pathname includes query params', () => {
198217
it('Should not render query breadcrumb', () => {
199-
const { Breadcrumbs } = render({ pathname: '/one?mock=query' });
200-
expect(Breadcrumbs.text()).toBe('Home / One');
218+
const { breadcrumbs } = render({ pathname: '/one?mock=query' });
219+
expect(breadcrumbs).toBe('Home / One');
201220
});
202221
});
203222

204223
describe('When pathname includes a trailing slash', () => {
205224
it('Should ignore the trailing slash', () => {
206-
const { Breadcrumbs } = render({ pathname: '/one/' });
207-
expect(Breadcrumbs.text()).toBe('Home / One');
225+
const { breadcrumbs } = render({ pathname: '/one/' });
226+
expect(breadcrumbs).toBe('Home / One');
208227
});
209228
});
210229

211230
describe('Options', () => {
212231
describe('excludePaths', () => {
213232
it('Should not return breadcrumbs for specified paths', () => {
214-
const { Breadcrumbs } = render({ pathname: '/one/two', options: { excludePaths: ['/', '/one'] } });
215-
expect(Breadcrumbs.text()).toBe('Two');
233+
const { breadcrumbs } = render({ pathname: '/one/two', options: { excludePaths: ['/', '/one'] } });
234+
expect(breadcrumbs).toBe('Two');
216235
});
217236
});
218237
});

0 commit comments

Comments
 (0)