Im using jest to test a simple button in React and it keeps failing. My latest iteration complains about render. I'm new to testing and I've been at it for a while and cannot figure this out. What am I missing here?
Here's my App.js
function clickMe() {
alert("Hello")
}
function App() {
return (
<div className="App">
<button id="btn" onClick={clickMe}>Click Me!!</button>
</div>
)
}
export default App;
Here's my App.test.js
import React from 'react'
import {render} from 'react-dom'
import App from './App'
test("Click", () => {
const {container} = render(<App />)
const button = getByTestId(container, 'btn')
fireEvent.click(button)
})
You can simulate some events with the enzyme library
For this first install this by npm, then import that
import {shallow} from 'enzyme';
After using this structure to simulate a click on a bottom
Create a wrapper
let wrapper = shallow(<App />);
beforeEach( ()=>{
wrapper = shallow(<CounterApp />);
});
This creates a simulation of render components and gives you the capacity to simulate events, this method is working in my project counterApp
test('Click', ()=>{
wrapper.find('button').at(0).simulate('click');
expect(//The action of your botton).toBe(//the result expected);
});
Not exactly the same but something like this also worked
import { shallow } from 'enzyme'
import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'
import App from './App'
configure({ adapter: new Adapter() })
it('renders the link inside the output area', () => {
const output = shallow(<App />)
expect(output.find('div').find('button').length).toEqual(1)
})
Related
I have one component that that use one customized hook and I need to write some test and make sure I mock the hook. How can I mock the customized hook to have unit test for my component like the code of hook does not even exist?
import "./styles.css";
import useAPICall from "#src/hooks/useAPICall ";
export default function App() {
const { onAPICall } = useAPICall(123);
const handleOnClick = useCallback(() => {
onAPICall();
});
return (
<div className="App">
<button onClick={handleOnClick}>Click</button>
</div>
);
}
///test.tsx all I know is this. but I am not sure how I can use mockImplementation that does not return anything
jest.mock('#src/hooks/useAPICall', () => ({
onAPICall: () => jest.fn(),
}));
You can do it in three simple steps:
Import the module which you want to mock
Then mock the module
Provide the return value of the mocked module.
import React from 'react';
import { render } from '#testing-library/react';
import userEvent from '#testing-library/user-event';
import App from './App';
import useAPICall from "#src/hooks/useAPICall "; // 1st step
jest.mock('#src/hooks/useAPICall'); //2nd step
test('can call useAPICall hook', () => {
useAPICall.mockReturnValue({ onAPICall: jest.fn() }); // 3rd step
const { getByRole } = render(<NewApp />);
userEvent.click(getByRole('button'));
expect(useAPICall).toBeCalled();
});
For abstraction purpose, the app I work on has a custom provider that wraps a couple of other providers (like IntlProvider and CookiesProvider). The version of react-intl we use in our app is still v2 (react-intl#2.8.0). A simplified version of my App.js is:
App.js
return (
<Provider
value={{
localeData,
env,
data
}}>
<IntlProvider locale={language} key={language} messages={allMessages}>
{props.children}
</IntlProvider>
</Provider>
)
I have setup a custom render to test components in my app. My custom render looks exactly as it is specified in the react-intl-docs. I have followed the official setup guides from react-testing-library.
import React from "react";
import {render} from "#testing-library/react";
import {MyProvider} from "MyProvider";
const MyTestProvider = ({children}) => {
return <MyProvider>{children}</MyProvider>;
};
const myTestRender = (ui, options) => render(ui, {wrapper: MyTestProvider, ...options});
export * from "#testing-library/react";
export {myTestRender as render};
I then render my component under test as follows:
import {render as renderSC} from "test-utils";
import MyComponentUnderTest from 'MyComponentUnderTest';
test("does my component render", () => {
const {getByText} = renderSC(<MyComponentUnderTest />);
});
I get an error from react-intl which indicates it is warning, but the component that is rendered in test is empty.
console.error
Warning: IntlProvider.shouldComponentUpdate(): Returned undefined instead of a boolean value. Make sure to return true or false.
This is what my component renders in test:
<body>
<div />
</body>
Is anyone able to advise what I might be doing wrong?
I think your exports make this problem, try these instead:
import React from "react";
import {render} from "#testing-library/react";
import {MyProvider} from "MyProvider";
const MyTestProvider = ({children}) => {
return <MyProvider>{children}</MyProvider>;
};
const myTestRender = (ui, options) => render(ui, {wrapper: MyTestProvider, ...options});
export default myTestRender;
and then use your custom renderer this way:
import renderSC from "test-utils";
import MyComponentUnderTest from 'MyComponentUnderTest';
test("does my component render", () => {
const {getByText} = renderSC(<MyComponentUnderTest />);
});
So I was able to confirm that nothing was wrong with testing-library or with react-intl. The problem was the app I work on had a module mock that mocked out the functionality of react-intl. This was done for convenience when working with unit tests with Enzyme. However this module mock was stripping out all functionality I needed for IntlProvider and that was the reason I was seeing an empty div when I render the testing-library test with a wrapper.
I am trying to write the testing file for the following code.
with my present code
import React from 'react';
import renderer from 'react-test-renderer';
// import { mount } from 'enzyme';
import LazyToastMessage from '../LazyToastMessage';
import IntlHelper from "test/util/Mount";
import nls from "src/nls/homepageHeader.json";
describe('the suspended toast message component renders correctly', () => {
const mountWithNLS = new IntlHelper(nls);
it('LazyToastMessage fallback', () => {
const mockHandler = jest.fn();
const wrapper = renderer.create(mountWithNLS.mountWithIntl(
<LazyToastMessage
state
message="test message"
iconType="success"
handleToasterStateChange={mockHandler}
/>)
)
expect(wrapper.toJSON()).toMatchSnapshot();
})
});
The result of the snapshot is giving as null. How can I test the updated component and take its snapshot?
The Lazy component is the following:
import React, {lazy, Suspense} from "react";
import {IAppProps} from 'src/js/components/misc/ToastMessage'
const LazyToastMessage = lazy(() =>
import(/* webpackChunkName: "toast-message" */ "./ToastMessage"),
);
export default function(props: IAppProps) {
return (
<Suspense fallback={null}>
<LazyToastMessage {...props} />
</Suspense>
);
}
To test it properly, you have to wrap your lazily loaded component in Suspense in test.
First, in your component:
export const LazyToastMessage = ...
Then, in your test:
import SuspendedLazyToastMesssage, {LazyToastMessage} from '../LazyToastMessage';
.
.
.
const wrapper = renderer.create(mountIthNLS(mountWithIntl(
<Suspense fallback=null>
<SuspendedLazyToastMessage/>
</Suspense>
));
await LazyToastMessage;
expect(wrapper.toJSON()).toMatchSnapshot();
Or something like that, but you get the idea...
I need to access and test a method of a child component in react using Jest. I am not using Enzyme, so this is not a duplicate of this question or this question. I would like to use React Testing Library instead of Enzyme.
Earlier I was happily accessing the methods I needed to test like this:
import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import App from "./App";
let container: any = null;
beforeEach(() => {
// setup a DOM element as a render target
container = document.createElement("div");
document.body.appendChild(container);
});
afterEach(() => {
// cleanup on exiting
unmountComponentAtNode(container);
container.remove();
container = null;
});
test("methodToTest should do what I want it to", () => {
const { methodToTest } = render(<App />, container);
methodToTest("some input");
const output = document.querySelector(".outputFromMethod");
expect(output.innerHTML).toBe("You gave me some input");
});
But now I need to wrap my <App /> component in withRouter() from react-router-dom, so I have to do something like this: (Based on the recipe suggested by React Testing Library)
import React from "react";
import { BrowserRouter as Router } from "react-router-dom";
import { render, unmountComponentAtNode } from "react-dom";
import App from "./App";
let container: any = null;
beforeEach(() => {
// setup a DOM element as a render target
container = document.createElement("div");
document.body.appendChild(container);
});
afterEach(() => {
// cleanup on exiting
unmountComponentAtNode(container);
container.remove();
container = null;
});
test("methodToTest should do what I want it to", () => {
// THIS DOESN'T WORK NOW FOR GETTING methodToTest
const { methodToTest } = render(<Router><App /></Router>, container);
const output = document.querySelector(".outputFromMethod");
expect(output.innerHTML).toBe("You gave me some input");
});
I understand that it's not ideal to try to test methods on a child component. But I need to do this because I have to have this component render inside of a <Router>. Is there any way to access the <App /> components methods without using Enzyme, or using React Testing Library if necessary?
You can't do that with Testing Library, that's against the principles. You're also using a strange style for testing. Have you tried to do this:
import React from "react";
import { BrowserRouter as Router } from "react-router-dom";
import { render } from "#testing-library/react";
import App from "./App";
import "#testing-library/jest-dom/extend-expect";
test("methodToTest should do what I want it to", () => {
const { getByText } = render(<Router><App /></Router>);
expect(getByText("You gave me some input")).toBeInTheDocument();
});
I want to write an integration test to assert that a when a parent component drills certain values or properties to a child component, that component receives said values and renders them properly. Below I have two component examples and an example test. Of course, the test is not accurate, but I'm wondering how I can use enzyme to accomplish this? Thanks!
sampleComponent.js:
import React from 'react';
const SampleComponent = () => (
<div test-attr="div">
<SampleChildComponent title="Sample title" />
</div>
);
export default SampleComponent;
sampleChildComponent.js:
import React from 'react';
const SampleChildComponent = ({ title }) => <h3 test-attr="h">{title}</h3>;
export default SampleChildComponent;
sampleComponent.test.js:
import React from 'react';
import { shallow } from 'enzyme';
import SampleComponent from './sampleComponent';
import SampleChildComponent from './sampleChildComponent';
test('renders component without errors', () => {
const wrapper = shallow(<SampleComponent />);
const childWrapper = shallow(<SampleChildComponent />);
expect(childWrapper.text()).toEqual('sample title');
});
To render child components you should use mount instead of shallow:
import { mount } from 'enzyme'
import React from 'react'
import SampleChildComponent from './sampleChildComponent'
import SampleComponent from './sampleComponent'
test('renders component without errors', () => {
const wrapper = mount(<SampleComponent />)
expect(wrapper.find(SampleChildComponent).text()).toEqual('sample title')
})