props are not receiving from test file to class components in JEST - reactjs

File-
import React from "react";
import PropTypes from "prop-types";
import * as css from "#/utils/css";
class CheckFile extends React.Component {
static propTypes = {
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
timeout: PropTypes.number
};
state = {
active: false
};
componentDidUpdate(oldProps) {
//not receiving props
}
componentWillUnmount() {
window.clearTimeout(this.timeoutEl);
}
render() {
return (
<div>
</div>
);
}
}
export default CheckFile;
Test File:
import React from "react";
import renderer from "react-test-renderer";
import { render } from "#testing-library/react";
import CheckFile from "../index";
describe("Test for PullToRefresh", () => {
it("check for snapshot", () => {
const Comp = () => <CheckFile />;
const props1 = { id: "test-id1", timeout: 1000, text: "testing snackbar1" };
const component = renderer.create(<Comp {...props1} />);
const { rerender } = render(<Comp />);
const props2 = {
id: "test-id2",
timeout: 1000,
text: "testing snackbar1"
};
rerender(<Comp {...props2} />);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
});
When I send Props from test file it is not received by class component.Showing undefined .
When I send Props from test file it is not received by class component.Showing undefined .
When I send Props from test file it is not received by class component.Showing undefined .

I don't understand why you are trying to test CheckFile but then render it in a locally declared component and then don't pass any props through to it.
describe("Test for PullToRefresh", () => {
it("check for snapshot", () => {
const Comp = () => <CheckFile />; // <-- no props passed here!!
const props1 = { id: "test-id1", timeout: 1000, text: "testing snackbar1" };
const component = renderer.create(<Comp {...props1} />);
const { rerender } = render(<Comp />);
const props2 = {
id: "test-id2",
timeout: 1000,
text: "testing snackbar1"
};
rerender(<Comp {...props2} />);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
});
Either proxy the props through to CheckFile:
const Comp = (props) => <CheckFile {...props} />;
Or just use CheckFile directly in test:
describe("Test for PullToRefresh", () => {
it("check for snapshot", () => {
const props1 = { id: "test-id1", timeout: 1000, text: "testing snackbar1" };
const component = renderer.create(<CheckFile {...props1} />);
const { rerender } = render(<CheckFile />);
const props2 = {
id: "test-id2",
timeout: 1000,
text: "testing snackbar1"
};
rerender(<CheckFile {...props2} />);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
});

Related

React component test case coverage of inline functions

Can someone help me cover this test case, I am not able to figure out how to cover this inline function
Note: DropdownField is a wrapper component and contains the actual which is imported from
import { Field } from "redux-form";
dropdown input inside
I have tried to call mockfunction and jest.fn() but nothing works, Any help will be appreciated because I am totally blank at the moment. Thanks in advance to all the wonderful devs
import React from "react";
import DropdownField from "components/FormFields/DropdownField";
import get from "lodash/get";
 
const AddressLookup = props => {
const {
change,
formValues,
fetchAddressLookup,
postalCodeOptions,
type = "delivery",
placeholder = "type_to_search",
field
} = props;
const selectedDeliveryMethod = get(formValues, "delivery_method", {});
 
return (
<DropdownField
placeholder={placeholder}
options={postalCodeOptions}
{...selectedDeliveryMethod.fields.zip_code}
isSearchable={true}
field={field}
onInputChange={value => {
if (value.length >= 2) fetchAddressLookup({ q: value });
}}
onChange={({ value }) => {
const [city, state, zipCode] = value.split("-");
change(field, value);
change(`${type}_state`, state);
change(`${type}_city`, city);
change(`${type}_zip_code`, zipCode);
}}
/>
);
};
 
export default AddressLookup;
I have tried this approach but It failed to cover. First test case covers the UI part only as you can see it is matching to snapshot. In second test cases I removed some code and commented some because nothing works
import * as React from 'react';
import { render, fireEvent, wait } from '#testing-library/react';
import { IntlProvider } from 'react-intl';
import { Provider } from 'react-redux';
import { reduxForm } from 'redux-form';
import configureStore from 'redux-mock-store';
import messages from '__fixtures__/messages.json';
import AddressLookup from '../index';
const DecoratedAddressLookup = reduxForm({ form: 'testForm' })(AddressLookup);
const testProps = {
change: jest.fn(),
fetchAddressLookup: jest.fn(),
postalCodeOptions: [
{
name: 'abc-abcd-1234',
value: 'abc-abcd-1234',
},
],
formValues: {
delivery_method: {
fields: {
zip_code: 'BD-BDBD-1234',
},
},
},
field: 'zip_code',
};
describe('<AddressLookup />', () => {
let testStore;
let addressField;
const mockStore = configureStore([]);
const store = mockStore({});
const spy = jest.fn();
beforeAll(() => {
testStore = store;
});
const renderComponent = () => {
return render(
<Provider store={testStore}>
<IntlProvider locale='en' messages={messages}>
<DecoratedAddressLookup
{...testProps}
onInputChange={spy}
onChange={spy}
/>
</IntlProvider>
</Provider>
);
};
it('should render and match the snapshot', () => {
const {
getByTestId,
container: { firstChild },
} = renderComponent();
addressField = getByTestId('zip_code');
expect(firstChild).toMatchSnapshot();
});
it('should type a value', async () => {
addressField = addressField.querySelector('input');
// expect(addressField).toBeTruthy();
// console.log('addressField', addressField);
// const input = screen.getByTestId('add-word-input');
fireEvent.change(addressField, { target: { value: 'abc-abcd-1234' } });
expect(addressField).toHaveValue('abc-abcd-1234');
// expect(testProps.change).toBeCalled();
await wait(() => {
expect(spy).toHaveBeenCalledTimes(1);
});
});
});

useSelector of Undefined

Hi I am writting unit testing for a component it has redux in it. While testing it , throws an error UseSelector state undefined. UseSelector will be updated once after getting response from the api. Till that its value is undefined. But while unit tetsing it throws error on the first itself . How to overcome this issue.
Test File
import React from 'react';
import { render, fireEvent } from '#testing-library/react';
import { act } from 'react-dom/test-utils';
import '#testing-library/jest-dom/extend-expect';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import LinkApplication from '../index';
import {reducer} from '../../../redux/summary/reducer';
let INITIAL_STATES = {
isFetching: false,
errorMessage: "",
requestExtensionErrorMessage: "",
requestExtensionSuccessMessage: "",
linkApplicationSuccess: "",
linkApplicationFailure: null,
linkLoanSuccessMessage: "",
linkLoanErrorMessage: "",
LinkApplicationErrorMessage:"",
};
function renderWithRedux(
component,
{ INITIAL_STATES, store = createStore(reducer, INITIAL_STATES) } = {},
) {
return {
...render(<Provider store={store}>{component}</Provider>),
};
}
it('sumbits the form', async () => {
const onSubmit = jest.fn();
const { getByText, getByTestId } = renderWithRedux(
<LinkApplication onSubmit={onSubmit} />,
);
const Dob_Input = getByTestId('dob-input');
const Phone_Input = getByTestId('phone-input');
const form = getByTestId('form');
act(() => {
fireEvent.keyPress(Dob_Input, {
target: { value: '1995-09-27' },
});
fireEvent.keyPress(Phone_Input, { target: { value: '9500902621' } });
});
expect(Dob_Input.value).toBe('1995-09-27');
expect(Phone_Input.value).toBe('9500902621');
await act(() => {
fireEvent.submit(form);
});
expect(onSubmit).not.toHaveBeenCalled();
})
Component
const LinkApplication = () => {
const dispatch = useDispatch();
let LinkApplicationErrorMessage = useSelector(
state => state.summary.linkApplicationFailure
);
}
Error
TypeError: Cannot read property 'linkApplicationFailure' of undefined
const dispatch = useDispatch();
let LinkApplicationErrorMessage = useSelector(
state => state.summary.linkApplicationFailure
^
);
Please help me with that.
I think you need to mock react-redux
import * as React from 'react';
import { shallow } from 'enzyme';
jest.mock('react-redux', () => ({
useDispatch: () => {},
useSelector: () => ({
your: 'state',
}),
}));
import Component from './index';
describe('Test component', () => {
it('Should render and match the snapshot', () => {
const wrapper = shallow(<Component />);
});
});

Unit testing Apollo Graphql in React using Hooks

I am trying to create a unit test using React and Apollo Graphql, however I keep getting this error:
Watch Usage: Press w to show more. console.error node_modules/react-test-renderer/cjs/react-test-renderer.development.js:104
Warning: An update to ThemeHandler inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
This ensures that you're testing the behavior the user would see in the browser.
in ThemeHandler (at theme-handler.spec.tsx:51)
in ApolloProvider (created by MockedProvider)
in MockedProvider (at theme-handler.spec.tsx:50)
Here is my code:
import { createMuiTheme, MuiThemeProvider } from '#material-ui/core';
import * as Sentry from '#sentry/browser';
import React, { useState } from 'react';
import { BrandTheme, useGetBrandThemeQuery } from '../../generated/graphql';
/**
* Handles the app theme. Will set the default theme or the brand theme taken from the backend.
*/
export default function ThemeHandler(props: React.PropsWithChildren<any>): React.ReactElement {
const brandId = Number(process.env.REACT_APP_BRAND);
// Default Onyo theme
const [theme, setTheme] = useState({
palette: {
primary: { main: '#f65a02' },
secondary: { main: '#520075' },
},
typography: {
fontFamily: 'Quicksand, sans-serif',
},
});
useGetBrandThemeQuery({
variables: { brandId },
skip: brandId <= 0,
onCompleted: data => {
if (
!data.brandTheme ||
!data.brandTheme.brandThemeColor ||
data.brandTheme.brandThemeColor.length === 0
) {
console.warn('Empty brand theme returned, using default');
Sentry.captureMessage(`Empty brand theme for brandId: ${brandId}`, Sentry.Severity.Warning);
} else {
const palette = parseBrandPalette(data.brandTheme as BrandTheme);
setTheme({ ...theme, palette });
console.log('Theme', theme, data.brandTheme);
}
},
});
return <MuiThemeProvider theme={createMuiTheme(theme)}>{props.children}</MuiThemeProvider>;
}
function parseBrandPalette(brandTheme: BrandTheme) {
const pallete: any = {};
for (const color of brandTheme.brandThemeColor!) {
if (color && color.key === 'primaryColor') {
pallete.primary = { main: color.value };
} else if (color && color.key === 'darkPrimaryColor') {
pallete.secondary = { main: color.value };
}
}
return pallete;
}
And my test:
import renderer from 'react-test-renderer';
import React from 'react';
import ThemeHandler from './theme-handler';
import { MockedProvider, wait } from '#apollo/react-testing';
import { GetBrandThemeDocument } from '../../generated/graphql';
import { Button } from '#material-ui/core';
const { act } = renderer;
describe('Theme Handler', () => {
const originalEnv = process.env;
beforeEach(() => {
// https://stackoverflow.com/questions/48033841/test-process-env-with-jest/48042799
jest.resetModules();
process.env = { ...originalEnv };
delete process.env.REACT_APP_BRAND;
});
afterEach(() => {
process.env = originalEnv;
});
it('should use a theme retrieved from the backend', async () => {
process.env.REACT_APP_BRAND = '39';
const mocks = [
{
request: {
query: GetBrandThemeDocument,
variables: { brandId: 39 },
},
result: {
data: {
brandTheme: {
brandThemeColor: [
{ key: 'primaryColor', value: '#182335' },
{ key: 'darkPrimaryColor', value: '#161F2F' },
],
},
},
},
},
];
let wrapper;
act(() => {
wrapper = renderer.create(
<MockedProvider mocks={mocks} addTypename={false}>
<ThemeHandler>
<Button color='primary' id='test-obj'>
Hello world!
</Button>
</ThemeHandler>
</MockedProvider>
);
});
await wait(0);
expect(wrapper).toBeTruthy();
});
});
I also tried to use Enzyme's mount instead of the React test renderer, but the result is the same.
As far as I could tell, this error is being caused because I am changing the current state using an async function and hooks. But I am not sure what could I do differently for this to work.
I solved my problem by wrapping everything on my test with act. I believe that this error was happening because part of the test was wrapped in act, but the async part wasn't, so the change was happening outside the scope of this function.
Here is the updated test, that is passing:
import React from 'react';
import ThemeHandler from './theme-handler';
import { MockedProvider, wait } from '#apollo/react-testing';
import { GetBrandThemeDocument } from '../../generated/graphql';
import { Button } from '#material-ui/core';
import { mount } from 'enzyme';
import { act } from 'react-dom/test-utils';
describe('Theme Handler', () => {
const originalEnv = process.env;
beforeEach(() => {
// https://stackoverflow.com/questions/48033841/test-process-env-with-jest/48042799
jest.resetModules();
process.env = { ...originalEnv };
delete process.env.REACT_APP_BRAND;
});
afterEach(() => {
process.env = originalEnv;
});
it('should use a theme retrieved from the backend', async () => {
process.env.REACT_APP_BRAND = '39';
await act(async () => {
const mocks = [
{
request: {
query: GetBrandThemeDocument,
variables: { brandId: 39 },
},
result: {
data: {
brandTheme: {
brandThemeColor: [
{ key: 'primaryColor', value: '#182335' },
{ key: 'darkPrimaryColor', value: '#161F2F' },
],
},
},
},
},
];
const wrapper = mount(
<MockedProvider mocks={mocks} addTypename={false}>
<ThemeHandler>
<Button color='primary' id='test-obj'>
Hello world!
</Button>
</ThemeHandler>
</MockedProvider>
);
expect(wrapper).toBeTruthy();
await wait(0);
wrapper.update();
expect(wrapper.find('#test-obj')).toBeTruthy();
});
});
});

Redux form test using jest

I am trying to test redux form submit for some code similar to this file.
https://github.com/marmelab/admin-on-rest/blob/master/src/mui/auth/Login.js
My code is like this
const middlewares = [];
const mockStore = configureMockStore(middlewares);
it("submit button", () => {
userLogin = jest.fn();
const initialState = {
admin: {
notification: {
text: "",
type: "info"
}
},
};
store = mockStore(initialState);
tn = label => label;
const props = {
submitting: false,
theme: customTheme,
translate: tn,
store,
location: {
state: {
nextPathname: "/"
}
},
userLogin: userLogin
};
container = mount(
<Provider store={store}>
<TranslationProvider locale="en">
<Login {...props} /> //Login is connected component
</TranslationProvider>
</Provider>
,
{
context: { store: mockStore(initialState) }
}
);
const username = container.find("TextField").first();
username.simulate("change", { target: { value: "admin" } });
const password = container.find("TextField").last();
password.simulate("change", { target: { value: "Superuser" } });
const form = container.find("form");
form.simulate("submit");
console.log(username.debug());
expect(userLogin).toHaveBeenCalled();
});
I face two problems.
When I print the username then I dont see the update value that I update through simulate.
Secondly, the expect clause fails. How do I ensure that userLogin function in my code got called.
Expected mock function to have been called.
This is how I test my redux-forms using JEST snapshot testing.
import React from 'react'
import renderer from 'react-test-renderer'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import YourReduxFormComponent from 'path where it sitting in your project'
import { reduxForm } from 'redux-form'
jest.mock('react-dom')
const spy = jest.fn()
const initialStateValues = {/* initial state values that your form component expects */}
const Decorated = reduxForm({
form: 'testForm', onSubmit: { spy }
})(YourReduxFormComponent)
const formFieldValues = {/*Form field values*/}
it('YourReduxFormComponent renders correctly', () => {
const store = createStore((state) => state, initialStateValues)
const tree = renderer.create(
<Provider store={store}>
<Decorated
{...formFieldValues}
/>
</Provider>
).toJSON()
expect(tree).toMatchSnapshot()
})
//Make your own tests like above to test the values

Reactjs unit test

I have a LoginInfo component and under this component i am calling one more child component. I am trying to write unit test case for the components using jest,enzyme and react test utils. partially i have wrote the test cases but not sure how i can write test for child component (LoginInfoEdit). that line i am not able to cover.
import React from 'react';
import { LoginInfoEdit } from './LoginInfoEdit'
class LoginInfo extends React.Component {
constructor(props) {
super(props)
this.state = {
isLoginInfo: false
}
}
openEdit() {
this.setState({ isLoginInfo: true })
}
closeEdit() {
this.setState({ isLoginInfo: false })
}
OpenEditForUpdate(e) {
e.preventDefault();
this.openEdit();
}
render() {
return (
<div>
<form>
<div>
some text
</div>
<LoginInfoEdit loginid={this.props.loginid} openloginedit={this.state.isLoginInfo} onClose={this.closeEdit.bind(this)}>
</LoginInfoEdit>
</form>
</div>
)
}
}
export default LoginInfo
Unit test is Below--------
import React from 'react'
import { shallow } from 'enzyme';
import LoginInfo from './LoginInfo'
import LoginInfoEdit from './LoginInfoEdit'
const props = {
loginid: "1",
openloginedit: false,
};
describe('LoginInfo component', () => {
let LoginInfo = null;
let editButton = null;
beforeEach(() => {
LoginInfo = shallow(<LoginInfo {...props}/>);
editButton = LoginInfo.find('button[name="edit"]')
})
it('checks everything set properly', () => {
editButton.simulate('click', { preventDefault: () => { } });
expect(LoginInfo.state('isloginedit')).toEqual(true)
})
it('renders child', () => {
expect(LoginInfo.find('LoginInfoEdit').length).toEqual(1)
});
it('passes proper props to the child', () => {
const expected = {
loginid: "1",
openloginedit: false,
onClose: LoginInfo.instance().closeEdit.bind(this),
};
expect(LoginInfo.find('LoginInfoEdit').props()).toEqual(expected)
})
})
Usually in such cases I care only about checking whether we render the child and pass props we want to the child like:
let component;
const props = someProps;
beforeEach(() => { component = mount(<LoginInfo { ..props } />); });
it('renders child', () => {
expect(component.find('LoginInfoEdit').length).to.eql(1)
});
it('passes proper props to the child', () => {
const expected = {
loginid: someVal,
openloginedit: someotherVal,
onClose: component.instance().closeEdit,
};
expect(component.find('LoginInfoEdit').props()).to.eql(expected)
});
and then I just test the children (in this case, LoginInfoEdit) separately from the parent

Resources