0

I am working on testing a component using react-testing-library. The component has an alert which accepts a prop that comes from context to determine whether the alert is open or not.

const PersonRecord = () => {

  const {
    personSuccessAlert,
    setPersonSuccessAlert,
    updatePersonSuccessAlert,
    setUpdatePersonSuccessAlert,
  } = useContext(PeopleContext);

  return (
      {personSuccessAlert && (
        <div className="person-alert-container">
          <Alert
            ariaLabel="person-create-success-alert"
            icon="success"
            open={personSuccessAlert}
          />
        </div>
      )}
   )
 }

So the above code uses context to pull the value of personSuccessAlert from PeopleContext. If personSuccessAlert is true the alert will display. My context file is set up as follows:

import React, { createContext, useState } from 'react';

export const PeopleContext = createContext();

const PeopleContextProvider = ({ children }) => {
  const [personSuccessAlert, setPersonSuccessAlert] = useState(false);
  const [updatePersonSuccessAlert, setUpdatePersonSuccessAlert] = useState(
    false,
  );

  return (
    <PeopleContext.Provider
      value={{
        personSuccessAlert,
        updatePersonSuccessAlert,
        setPersonSuccessAlert,
        setUpdatePersonSuccessAlert,
      }}>
      {children}
    </PeopleContext.Provider>
  );
};

export default PeopleContextProvider;

Now I am trying to develop a test which passes personSuccessAlert = true to the PersonRecord component.

Here is what I have been trying:

export function renderWithEmptyPerson(
  ui,
  {
    providerProps,
    path = '/',
    route = '/',
    history = createMemoryHistory({ initialEntries: [route] }),
  },
) {
  return {
    ...render(
      <MockedProvider mocks={getEmptyPerson} addTypename={false}>
        <PeopleContextProvider {...providerProps}>
          <Router history={history}>
            <Route path={path} component={ui} />
          </Router>
        </PeopleContextProvider>
      </MockedProvider>,
    ),
  };
}

describe('empty person record rendering', () => {
  afterEach(cleanup);
  test('empty person', async () => {

    const providerProps = { value: true };

    const { getByText, queryByText, queryByLabelText } = renderWithEmptyPerson(
      PersonRecord,
      {
        providerProps,
        route: 'people/6d6ed1f4-8294-44de-9855-2999bdf9e3a7',
        path: 'people/:slug',
      },
    );
    expect(getByText('Loading...')).toBeInTheDocument();
  });
});

I have tried different variations of const providerProps = { value: true };. Replacing value with personSuccessAlert did not work.

Any advice or help is appreciated.

1 Answer 1

0

You are passing providerProps to the PeopleContextProvider, but the PeopleContextProvider is not doing anything with the props. You'll need to actually use those props, for example to set the initial state. You could try something like:

const PeopleContextProvider = ({ children, initialPersonSuccessAlert = false }) => {
  const [personSuccessAlert, setPersonSuccessAlert] = useState(initialPersonSuccessAlert);
  const [updatePersonSuccessAlert, setUpdatePersonSuccessAlert] = useState(
    false,
  );

  return (
    <PeopleContext.Provider
      value={{
        personSuccessAlert,
        updatePersonSuccessAlert,
        setPersonSuccessAlert,
        setUpdatePersonSuccessAlert,
      }}>
      {children}
    </PeopleContext.Provider>
  );
};

This would allow you to set the initial state of personSuccessAlert by passing in a initialPersonSuccessAlert prop. You could update your test like so:

const providerProps = { initialPersonSuccessAlert: true };

Alternatively, if you only wanted to make changes in your test file, you could consider updating the renderWithEmptyPerson function to use PeopleContext.Provider directly instead of the PeopleContextProvider component. That will allow you to set the context value however you like.

Sign up to request clarification or add additional context in comments.

2 Comments

Hmm, I think this might work, but it requires my to change my actual code rather than just my tests. I was hoping there is some way to mock out the value of personSuccessAlert just within my testing suite.
If you're dead-set on not modifying the code, then you could consider updating the renderWithEmptyPerson function to use PeopleContext.Provider directly instead of the PeopleContextProvider component. That will allow you to set the context value however you like. There is no other good way of doing it, short of mocking PeopleContextProvider, useContext, or useState, all of which I would strongly not recommend as it would make your tests extremely brittle.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.