Lukas Vis
Lukas Vis

Reputation: 475

How to initialize react usecontext state value during jest tests?

I have code where user can click on the ingredient and then I store his selected ingredient inside context and redirect him to a details page:

  const [, setSelectedItem] = useContext(itemContext);
  const [, setSelectedMealNumber] = useContext(selectedMealNumberContext);

  const editIngredient = (event: React.MouseEvent<HTMLElement>) => {
    setSelectedItem(ingredient);
    setSelectedMealNumber(mealNumber);
    router.push(`/i/${ingredient?.uid}`);
  };

However selectedItem is initialized as null in my context provider:

// Provider component

function ApiStore({ children }) {
  const [selectedItem, setSelectedItem] = useState(null);

So when testing details page:

it("renders the selected item productName", () => {
  const queryClient = new QueryClient();
  render(
    <ApiStore>
      <QueryClientProvider client={queryClient}>
        <IngredientExpanded />
      </QueryClientProvider>
    </ApiStore>
  );
  const productName = screen.getByText(FakeItem1.productName);
  expect(productName).toBeInTheDocument();
});

Test fails, because selectedItem is null.

At the moment I manually initialize the value in my context provider like this and my test succeeds:

  const [selectedItem, setSelectedItem] = useState(FakeItem1);

But since I need this value only for my tests and not the actual app, I have to remove it and set it back to null on my production app.

I don't need to mock everything since, everything else works. How can I simply inject the selectedItem during my test?

Upvotes: 2

Views: 7956

Answers (1)

Lin Du
Lin Du

Reputation: 102672

The easiest way is to add value props for ApiStore component. Then you can provide the initial value for the context provider.

index.ts:

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

const ItemContext = React.createContext({
  selectedItem: null,
  setSelectedItem: (state) => {},
});

export const ApiStore = ({ children, value }) => {
  const [selectedItem, setSelectedItem] = useState(value);

  return <ItemContext.Provider value={{ selectedItem, setSelectedItem }}>{children}</ItemContext.Provider>;
};

export const IngredientExpanded = () => {
  const { selectedItem } = useContext(ItemContext);

  return <div>{selectedItem}</div>;
};

index.test.ts:

import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import React from 'react';
import { ApiStore, IngredientExpanded } from '.';

describe('72047880', () => {
  test('should find the selected item', () => {
    render(
      <ApiStore value={'product name'}>
        <IngredientExpanded />
      </ApiStore>
    );
    const productName = screen.getByText('product name');
    expect(productName).toBeInTheDocument();
  });

  test('should not find the selected item', () => {
    render(
      <ApiStore value={null}>
        <IngredientExpanded />
      </ApiStore>
    );
    const productName = screen.queryByText('product name');
    expect(productName).not.toBeInTheDocument();
  });
});

test result:

 PASS  stackoverflow/72047880/index.test.tsx (11.239 s)
  72047880
    ✓ should find the selected item (23 ms)
    ✓ should not find the selected item (3 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        12.855 s

Upvotes: 5

Related Questions