Unit testing route matching with React Router 2 - reactjs

I’m trying to add unit tests for a React application and would like to test the routes provided by React Router (2.0.1). I’d like to test whether specific paths that I supply will match a route. I am writing my tests using Mocha and expect.
I’ve looked through the documentation on the React Router repository, but the only testing guide I could see was explaining how to test a <Link /> and how it’s rendered.
Say I have the following code:
// import statements omitted for brevity
export const routes = (
<Route path="/" component={App}>
<IndexRoute component={Index} />
<Route path="/foo">
<IndexRoute component={FooIndex} />
<Route path="add" component={FooAdd} />
<Route path=":fooId" component={FooDetails} />
</Route>
</Route>
)
ReactDOM.render(
<Router history={browserHistory}>{routes}</Router>,
document.getElementById('app')
)
How can I test that the routes created in the routes variable would match the following:
/
/foo
/foo/add
/foo/25
But not routes like:
/foo/bar/12
/bar
Essentially I want to check that every expected URL format has a route that will match it and that unexpected URLs don't match any routes.
I’m not interested in the elements that are rendered by the routes, so don't want to base my tests on checking whether a specific thing is rendered, only that a matching route was found and preferably some way of checking that it was in fact the expected route (I'd guess checking what the name of the component is or something?)
Any help is gratefully appreciated.
Thanks

We test exactly this in our test for matchRoutes: https://github.com/ReactTraining/react-router/blob/v3/modules/__tests__/matchRoutes-test.js
You can follow this pattern. If you can't identify your routes by reference, you can indeed assert on the components that were rendered as well.
As matchRoutes isn't exported, you'll want to use the match helper (otherwise used for for server-side rendering) instead, and check renderProps.routes or renderProps.components.

Related

React router V3 route does not match if I put one extra letter uppercase

So, I am using react router V3, and surprisingly one detail as little as one uppercase letter makes one route to not match. So this does worl:
<Route
path="payments"
component={AccountBalance}
>
<Route path=":paymentId" component={AccountBalance} />
</Route>
While this doesn't produce any navigation
<Route
path="payments"
component={AccountBalance}
>
<Route path=":paymentID" component={AccountBalance} />
</Route>
The difference is paymentID vs paymentId.
Reading react router v3 docs, there is nothing suggesting that this should happen
The route path must be lowercase, for example, you can use,
<Route path=":payment_id" ... />
for example, in javascript,
let helloWorld;
and
let HelloWorld;
are not equal, becouse theese variables were not written equal.

Can react router have a route with multiple option parameters where (e.g.) both are required, or none

Using react-router-dom I have a route like so:
<Route path='/:year?/:month?' component={ThingUsingYearAndMonth} />
But really I want BOTH year and month to exist (e.g. /2018/Dec or /2017/Jan) or neither. I.e. just /2018 wouldn't match
I would probably handle that using two routes -- one for when both are provided and one for when neither are provided:
<Route path='/:year/:month' component={ThingUsingYearAndMonth} />
<Route path='/' exact component={ThingUsingYearAndMonth} />
Try providing explicit parameters with regex:
<Route path='/:year(\\d{4})?/:month([A-Za-z]+)?' component={ThingUsingYearAndMonth} />
I don't think there is any mechanism provided by the react-router-dom to validate the route params. You are better off creating your own Higher Order Component and validate the route params in it. Or you can use regex to validate your params in the route itself.

react-router for navigating directory

I am building a component in my app that allows the user to navigate a directory which contains sub-directories and files. There is no limit on the number of sub-directories.
I would like to use the URL to indicate position with the sub-directories. For example, take this structure:
- dir
-- sub-dir1
---- sub-dir2
------ sub-dir5
-------- image.jpg
---- sub-dir3
---- sub-dir4
If someone has navigated to sub-dir5 then I would like the URL to show:
`myapp.com/dir/sub-dir1/sub-dir2/sub-dir5`
While I know how to do this if the folder structure was known in advance using :param values, I'm not sure about how to tackle setting up the routes when there could be any number of sub-directories.
I'm using react-router v4
Only way to do this is to create a root route which will accept one (optional) param which is your file system path.
<Route exact path='/:path' component={ DirListing } />
Then you need to parse it (split by /) in your component to make sure it is valid. Once you got your path, you can load file list and show it to a user.
I would go even that far that you don't really need React Router for this, as you are going to end up parsing the routes yourself anyway. React Router makes is a bit easier though.
One last note, make sure you redirect all of the requests back to your react app (or you will end up with server side listing).
How about,
import React from "react";
import ReactDOM from "react-dom";
import {
BrowserRouter as Router,
Link,
Route,
Switch
} from "react-router-dom";
ReactDOM.render(
<Router>
<Switch>
<Route exact strict path="/:folderPath+/" component={DirList} />
<Route path="/:folderPath+/:fileName" component={Detail} />
</Switch>
</Router>,
node
);
or otherwise for the rendering part,
ReactDOM.render(
<Router>
<Switch>
<Route exact strict path="/:folderPath+/:fileName" component={Detail} />
<Route path="/:folderPath+/" component={DirList} />
</Switch>
</Router>,
node
);
This takes route name which ends with / to <DirList /> otherwise to <Detail />.
strict is needed to distinguish whether a path contains ending /.
exact is required since strict allows sub paths. Otherwise a path some/folder/file.png can fall into /:folderPath+/ when it comes to the upper case of the code example, and a path some/folder/ can fall into /:folderPath+/:fileName for the lower case of the example by recognizing
the path with params: { folderPath: 'some', fileName: 'folder/' }
as referred in Route path doc, Route path regExp rules
Route exact and strict doc

How do I avoid rendering a component when another component in a similar path has already rendered when using URL params in React Router v4?

I'm trying to create RESTful routes for my application, but I'm having problems when it comes to routes with URL params.
Here are the routes that I want to have:
/accounts
/accounts/new
/accounts/edit
/accounts/:id
These is what my router looks like:
<Router>
<Route exact path="/accounts" component={AccountsList} />
<Route exact path="/accounts/new" component={AccountCreate} />
<Route exact path="/accounts/edit" component={AccountUpdate} />
<Route exact path="/accounts/:id" component={AccountDetail} />
</Router>
/accounts works fine, but when I go to /accounts/new or /accounts/edit, it also renders AccountDetail which is supposed to be located at /accounts/:id.
For the record, that I get that this is the correct behavior since /accounts/:id technically matches /accounts/new and /accounts/edit.
My question is if there's a way to make :id match with a specific pattern only (numbers only).
Try the < Switch> component of reactRouter.
Renders the first child < Route> or < Redirect> that matches the
location.
I think it's exactly what you are looking for.

ReactJS Values In The URL Always Visible

I have a filter system for my products in ReactJS which basically has the following:
http://localhost:3000/category/women/subcategory/tops/sorting/null/price/null/size/null/color/null/brands/null/merchants/null
The Route is as follows:
<Router>
<Route path="/category/:cat/subcategory/:subCat/sorting/:sorting/price/:price/size/:size/color/:color/brands/:brands/merchants/:merchants" component={Products} />
</Router>
The Problem is that I want to show filters in the URL in when they have a value other than null. Current my component works but I have to display every single filter in the URL with a null value by default, this is causing my URL to be extremely long. The only way I thought possible was to do a permutation combination of all the possible URLs in the filter and direct them all to { Products } which is extremely silly. There must be something in the Router component that I'm missing?
You need to use optional params in this case.
As and example if you want to accept both sorting/ascending/price and sorting/price you can write your path as follows assuming you use react router v4.
<Router>
<Route path="sorting/:sort?/price" component={Products} />
</Router>
You can read more about this here: React Router with optional path parameter

Resources