skip to Main Content

I am trying to test the below scenario with React Router V3. Based on the step prop, I set some state variables and then render the component. The correct screen is then displayed based on the props passed to

const TestComponent = ({
  languageData,
  locale,
  route: { step },
}) => {
  const [showTiles, setShowTiles] = useState(true);
  const [showAdsSearch, setShowAdsSearch] = useState(false);
  const [showBasicSearch, setShowBasicSearch] = useState(false);
  const [showSubmitterFields, setShowSubmitterFields] = useState(false);

  const viewHome = () => {
    setShowBasicSearch(false);
    setShowSubmitterFields(false);
    setShowAdsSearch(false);
    setShowTiles(true);
  };

  const viewBasicSearch = () => {
    setShowBasicSearch(true);
    setShowSubmitterFields(false);
    setShowAdsSearch(false);
    setShowTiles(false);
  };

  const viewAdSearch = () => {
    setShowBasicSearch(false);
    setShowSubmitterFields(false);
    setShowAdsSearch(true);
    setShowTiles(false);
  };

  const viewCreateSubmitterProfileFields = () => {
    setShowBasicSearch(false);
    setShowSubmitterFields(true);
    setShowAdsSearch(false);
    setShowTiles(false);
  };

  const stepMap = new Map([
    [1, viewHome],
    [2, viewCreateSubmitterProfileFields],
    [3, viewBasicSearch],
    [4, viewAdSearch],
  ]);

  useEffect(() => {
    const currentState = stepMap.get(step) || viewHome;
    currentState();
  }, [step]);

  if (Object.entries(languageData).length === 0) {
    return <ProgressCircle />;
  }

  return (
    <IntlProvider locale={locale} messages={languageData}>
      <UserContext.Consumer>
        {(user) => (Object.keys(user).length > 0 ? (
          <HomeView
            className={styles.grayBg}
            showAdsSearch={showAdsSearch}
            setShowAdsSearch={setShowAdsSearch}
            showSubmitterFields={showSubmitterFields}
            setShowSubmitterFields={setShowSubmitterFields}
            showBasicSearch={showBasicSearch}
            setShowBasicSearch={setShowBasicSearch}
            showTiles={showTiles}
            setShowTiles={setShowTiles}
          />
        ) : <div>NO USER CONTEXT SET IN ROOT MODULE</div>)}
      </UserContext.Consumer>
    </IntlProvider>
  );
};

The home component:

export function Home({
  showTiles,
  setShowTiles,
  showBasicSearch,
  setShowBasicSearch,
  showAdsSearch,
  setShowAdsSearch,
  showSubmitterFields,
  setShowSubmitterFields,
}) {

  return (
    <React.Fragment>
      <HeaderSection
        setShowBasicSearch={setShowBasicSearch}
        showBasicSearch={showBasicSearch}
        setShowTiles={setShowTiles}
        setShowAdsSearch={setShowAdsSearch}
        setSubmitterIdToView={setSubmitterIdToView}
        setSubmitterName={setSubmitterName}
        setShowSubmitterFields={setShowSubmitterFields}
      />
      <div id="home" className={styles.grayBgForHome}>
        {showTiles && (
          <TilesView
            setShowBasicSearch={setShowBasicSearch}
            setShowTiles={setShowTiles}
            setShowAdsSearch={setShowAdsSearch}
            showAdsSearch={showAdsSearch}
            showSubmitterFields={showSubmitterFields}
            setShowSubmitterFields={setShowSubmitterFields}
          />
        )}
        {showBasicSearch && (
          <React.Fragment>
            <h1 className={styles.headingText}>
              Search Submitter Profile
            </h1>
            <ConnectedBasicSearch/>
          </React.Fragment>
        )}
        {showAdsSearch && (
          <React.Fragment>
            <h1 className={styles.headingText}>
              Advanced Search Submitter Profile
            </h1>
            <ConnectedAdvancedSearch/>
          </React.Fragment>
        )}
        {showSubmitterFields && (
          <React.Fragment>
            <h1 className={styles.headingText}>Create Submitter Profile</h1>
            <ConnectedSubmitterProfile/>
          </React.Fragment>
        )}
      </div>
      <FooterSection />
    </React.Fragment>
  );
}

In my test, I have the below. What I am trying to do is render Home with step = 1 which should display the Tiles component. Then I click on the #basicSearchTile which is a
Link to /submitter-profile/basic-search and want to check for certain elements being displayed:

async function clickElement(container, selector) {
  const user = userEvent.setup();
  const element = container.querySelector(selector);
  await user.click(element);
}

async function checkDisplayed(container, selector, shouldBeDisplayed) {
  const element = container.querySelector(selector);
  if (shouldBeDisplayed) {
    expect(element).toBeInTheDocument();
  } else {
    expect(element).not.toBeInTheDocument();
  }
}

const props1 = {
  languageData: { intlKeyMock: 'intlValueMock' },
  locale: 'localeMock',
  route: { step: 1 },
};
const props2 = {
  languageData: { intlKeyMock: 'intlValueMock' },
  locale: 'localeMock',
  route: { step: 2 },
};
const props3 = {
  languageData: { intlKeyMock: 'intlValueMock' },
  locale: 'localeMock',
  route: { step: 3 },
};
const props4 = {
  languageData: { intlKeyMock: 'intlValueMock' },
  locale: 'localeMock',
  route: { step: 4 },
};

  describe('Navigation tests', () => {
    it('invalid submitterId on save for edit profile', async () => {
      const { container } = render(
        <Router initialEntries={['/submitter-profile']} history={createMemoryHistory()}>
          <UserContext.Provider value={loggedInUser}>
            <Route path="/" element={<TestableAxpSubmissionsWebSearchSubmitterProfile {...props1} />} />
            <Route path="/submitter-profile" element={<TestableAxpSubmissionsWebSearchSubmitterProfile {...props1} />} />
            <Route path="/submitter-profile/basic-search" element={<TestableAxpSubmissionsWebSearchSubmitterProfile {...props3} />} />
            <Route path="/submitter-profile/create" element={<TestableAxpSubmissionsWebSearchSubmitterProfile {...props2} />} />
            <Route path="/submitter-profile/advanced-search" element={<TestableAxpSubmissionsWebSearchSubmitterProfile {...props4} />} />
          </UserContext.Provider>
        </Router>
      );
      screen.debug();
      await clickElement(container, '#basicSearchTile');
      await clickElement(container, '#search-button');
      await clickElement(container, '#resultTableRowsubmitterId123');
      await clickElement(container, '#editToggle');
      await clickElement(container, '#saveButton');
      screen.debug();
      await checkDisplayed(container, '#responseModalMsg', true);
      await checkTextValue(container, '#responseModal', 'Must enter a valid value for Submitter ID.');
      await clickElement(container, '#responseModal');
      await checkDisplayed(container, '#responseModalMsg', false);
    });
});

However, whenever i use render, the screen.debug() calls are returning an empty body .

<body>
  <div />
</body>

Also I have added the route definitions in case they are helpful.
Routing in the app is working great. it is just the tests that I cannot get to work

const Routes = [
  <Route
    key="submitter-profile-route"
    path="/submitter-profile"
    moduleName="axp-submissions-web-search-submitter-profile"
    step={1}
  />,
  <Route
    key="create-submitter-profile-route"
    path="/submitter-profile/create"
    moduleName="axp-submissions-web-search-submitter-profile"
    step={2}
  />,
  <Route
    key="basic-search-submitter-profile-route"
    path="/submitter-profile/basic-search"
    moduleName="axp-submissions-web-search-submitter-profile"
    step={3}
  />,
  <Route
    key="advanced-search-submitter-profile-route"
    path="/submitter-profile/advanced-search"
    moduleName="axp-submissions-web-search-submitter-profile"
    step={4}
  />];

2

Answers


  1. I have added the route definitions in case they are helpful. Routing in the app is working great. it is just the tests that I cannot get to work.

    In first, it seems correctly set up. But in your test, you use render from @testing-library/react to render component but this doesn’t support react-router v3.

    I’m just thinking here that you need a Router component to navigate in your tests.

    I use createMemoryHistory from history here, because we need to create a history object first then pass it to the Router.

    If can’t find createMemoryHistory or no history yet, install it by doing npm install --save history.
    Then, create a router like the below sample to allow you simulate navigation in your tests.

    import { createMemoryHistory } from 'history';
    import { Router } from 'react-router';
    
    // ...
    
    it('invalid submitterId on save for edit profile', async () => {
     const history = createMemoryHistory();
     history.push('/');
    
     const { container } = render(
     <Router history={history}>
       <UserContext.Provider value={loggedInUser}>
         <Route path="/" element={<TestableAxpSubmissionsWebSearchSubmitterProfile {...props1} />} />
         <Route path="/submitter-profile" element={<TestableAxpSubmissionsWebSearchSubmitterProfile {...props1} />} />
         <Route path="/submitter-profile/basic-search" element={<TestableAxpSubmissionsWebSearchSubmitterProfile {...props3} />} />
         <Route path="/submitter-profile/create" element={<TestableAxpSubmissionsWebSearchSubmitterProfile {...props2} />} />
         <Route path="/submitter-profile/advanced-search" element={<TestableAxpSubmissionsWebSearchSubmitterProfile {...props4} />} />
       </UserContext.Provider>
     </Router>
     );
    
     // ...
    });
    
    Login or Signup to reply.
  2. The React-Router v3 Route component doesn’t have an element prop, it has a component prop. Update the test code to use the component prop and pass a reference to the component instead of JSX.

    Be sure to also specify the routes in the inverse order of path specificity, e.g. render more specific paths before less specific paths.

    Example:

    describe('Navigation tests', () => {
      it('invalid submitterId on save for edit profile', async () => {
        const memoryHistory = createMemoryHistory();
    
        const { container } = render(
          <Router
            initialEntries={['/submitter-profile']}
            history={memoryHistory}
          >
            <UserContext.Provider value={loggedInUser}>
              <Route
                path="/submitter-profile/basic-search"
                component={TestableAxpSubmissionsWebSearchSubmitterProfile}
              />
              <Route
                path="/submitter-profile/create"
                component={TestableAxpSubmissionsWebSearchSubmitterProfile}
              />
              <Route
                path="/submitter-profile/advanced-search"
                component={TestableAxpSubmissionsWebSearchSubmitterProfile}
              />
              <Route
                path="/submitter-profile"
                component={TestableAxpSubmissionsWebSearchSubmitterProfile}
              />
              <Route
                path="/"
                component={TestableAxpSubmissionsWebSearchSubmitterProfile}
              />
            </UserContext.Provider>
          </Router>
        );
    
        ...
      });
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search