'Testing react component that uses Context - change state of component under test

I want to test the following React component

import React, { useContext, useState } from "react";
import { IntlProvider } from "react-intl";

export const Context = React.createContext();
const defaultLocale = navigator.language;

const LocalizationWrapper = (props) => {
  const [locale, setLocale] = useState(defaultLocale);

  function changeLocale(newLocale) {
    setLocale(newLocale);
  }

  return (
    <Context.Provider value={{ locale, changeLocale }}>
      <IntlProvider locale={locale}>{props.children}</IntlProvider>
    </Context.Provider>
  );
};

For this, I have written test

import React from 'react';
import { render, unmountComponentAtNode } from "react-dom";
import { FormattedDate } from "react-intl";
import { act } from "react-dom/test-utils";
import LocalizationWrapper from './localizationWrapper';

let container = null;
beforeEach(() => {
    container = document.createElement("div");
    document.body.appendChild(container);
});

afterEach(() => {
    unmountComponentAtNode(container);
    container.remove();
    container = null;
});

it("date formatted with default locale", () => { 
    act(() => {
        render(
            <LocalizationWrapper >
                <FormattedDate value={new Date("2021-04-23")} />
            </LocalizationWrapper>, container);
    });

    expect(container.textContent).toBe("4/23/2021");
});

How to add a test case that changes the locale that is part of LocalizationWrapper state, by using context or by changing state directly? From code outside of test I use context to change locale like so:

const context = useContext(Context);
context.changeLocale(locale);


Solution 1:[1]

You can render the FormattedDate component inside a test component so that you can get the context value. Then you can invoke the context.changeLocale function.

E.g.

index.jsx:

import React, { useState } from 'react';
import { IntlProvider } from 'react-intl';

export const Context = React.createContext();
const defaultLocale = navigator.language;

export const LocalizationWrapper = (props) => {
  const [locale, setLocale] = useState(defaultLocale);

  function changeLocale(newLocale) {
    setLocale(newLocale);
  }

  return (
    <Context.Provider value={{ locale, changeLocale }}>
      <IntlProvider locale={locale}>{props.children}</IntlProvider>
    </Context.Provider>
  );
};

index.test.jsx:

import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { act } from 'react-dom/test-utils';
import { FormattedDate } from 'react-intl';
import { LocalizationWrapper } from '.';
import { Context } from './';

describe('67228107', () => {
  let container;
  beforeEach(() => {
    container = document.createElement('div');
    document.body.appendChild(container);
  });

  afterEach(() => {
    unmountComponentAtNode(container);
    container.remove();
    container = null;
  });

  it('date formatted with default locale', () => {
    let renderedContext;
    class TestComponent extends React.PureComponent {
      static contextType = Context;
      render() {
        renderedContext = this.context;
        return <FormattedDate value={new Date('2021-04-23')} />;
      }
    }
    act(() => {
      render(
        <LocalizationWrapper>
          <TestComponent />
        </LocalizationWrapper>,
        container
      );
    });

    expect(container.textContent).toBe('4/23/2021');
    act(() => {
      renderedContext.changeLocale('fr');
    });
    expect(renderedContext.locale).toBe('fr');
  });
});

Test result:

 PASS  stackoverflow/67228107/index.test.tsx (10.33 s)
  67228107
    ? date formatted with default locale (36 ms)

-----------|---------|----------|---------|---------|-------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------|---------|----------|---------|---------|-------------------
All files  |     100 |      100 |     100 |     100 |                   
 index.jsx |     100 |      100 |     100 |     100 |                   
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        11.615 s

package versions:

"react": "^16.14.0",
"react-dom": "^16.14.0",
"jest": "^26.6.3"

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 slideshowp2