How to create unit test for URL params for React Router using Enzyme
Asked Answered
H

1

12

I am trying to put url params under test using Enzyme of React Router. The application is simple so far. I have App.jsx that has a <Router /> component with a <Switch /> component and two <Route /> components.

Any help would be appreciated in setting up a test to take a URL as path from <Route /> and return a value for the path stub in a child <Files /> component.

I am completely new to testing, so please link docs, if you have them, and please pseudo-code or demonstrate an overview of your approach so that I can put it into proper context.

I have not seen any adequate or contextualized methods for testing the URL param functionality that suit my level of understanding. There was an answer here that suggests mocking with Jest, How to test components using new react router hooks? but there is not enough context for me to implement.

This is a basic standup of create-react-app:

function App() {
  const [user] = useState(sampleUser);

  return (
    <UserContext.Provider value={user}>
      <SiteHeader />
      <Router>
        <Switch>
          <Route path="/files/:fileId">
            <Files />
          </Route>
          <Route path="*">
            <header className="App-header">
              <img src={logo} className="App-logo" alt="logo" />
              <p>
                Edit
                <code>src/App.js</code>
                and save to reload.
              </p>
              <a
                className="App-link"
                href="https://reactjs.org"
                target="_blank"
                rel="noopener noreferrer"
              >
                Learn React
              </a>
            </header>
          </Route>
        </Switch>
      </Router>
    </UserContext.Provider>
  );
}

export default App;

I am interested in testing <Files /> in isolation, and passing in a URL. <Files /> destructures fileId from the useParams hook.

The component for Files looks like this:

import React from 'react';
// import PropTypes from 'prop-types';
import { useParams, Router } from 'react-router-dom';

const Files = () => {
  const { fileId } = useParams();
  return (
    <main>
      {`component for ${fileId}`}
    </main>
  );
};

Files.propTypes = {};

Files.defaultProps = {};

export default Files;

For my test, I am importing Files and Route, since Files inherits the path of Route using the useParams hook. I am mounting <Route path="/files/:fileId" component={Files} />, and I am wrapping that with <MemoryRouter initialEntries={['/files/mockId']} initialIndex={0}> to get state. the full code looks like this:

import React from 'react';
import { mount, shallow, configure, render } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import { MemoryRouter, matchPath, useParams } from 'react-router-dom';
import Files from './Files.jsx';
import Route from '../../App.jsx';

configure({ adapter: new Adapter() });

describe('FilesPage', () => {

  it('has fileId of `mockId`', () => {
    const wrapper = mount(
      <MemoryRouter initialEntries={['/page-tagger/mockId']} initialIndex={0}>
        <Route path="/page-tagger/:fileId" component={Files} />
        // <Files />
      </MemoryRouter>
    );

    // Get value fileId from <Files />
  });
});

I have tried many different approaches to get any value from the <Files /> component, but to no avail. I have tried a shallow(<Files />), but that leads to an error that useParams is undefined in the Files.jsx document. So, I mounted and used <MemoryRouter />. When I see what the wrapper.props() looks like, I can see that <Route /> has the props().children element for App has the path, and that the hook useParam is not a prop or anything for <Files />. The url in <MemoryRouter /> does not get passed down to children <Route /> nor <Files />.

Hydroid answered 12/12, 2019 at 19:6 Comment(3)
I am having this same issue, it just seems like the variable assigned from useParams{} is always undefined.Mythopoeic
any update on this? I also always see undefinedSpringwood
no updates, but I suppose the best approach would simply to assume that the URL is being parsed correctly, and to mock it as in the link at the top of this question. By mocking useParams(), you can create the expected values and test those.Hydroid
I
0

React Router is based on a package called history that handles all interactions with the browser.

You can create a Router and pass it a history instance to manage the URL during tests :

import {createMemoryHistory} from 'history';

test('', () => {
  const history = createMemoryHistory();
  mount(
    <Router history={history}>
      /* your components */
    </Router>
  )
})
Illegal answered 26/7, 2022 at 12:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.