'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 |