How to write unit test case for formik using react? - reactjs

I'm trying to write unit test case for react application. I using formik to handle form submission. In formik form we are using FieldArray component of formik. how to write test case for this?
import React from "react"
import { shallow } from "enzyme"
import { AdditionalCustomFields } from "./index"
import { additionalData, customFieldData} from "../../../../mockData"
import { settingStyles } from "../../../../../common/Styles"
import { withStyles } from "#material-ui/core/styles"
import PropTypes from "prop-types"
const props = {
values : {
additionalData,
customFieldData
}
}
const Composer = ({ classes}) =>{
return <AdditionalCustomFields classes={classes} {...props}/>
}
Composer.propTypes = {
classes: PropTypes.object.isRequired
}
const Composition = withStyles(settingStyles)(Composer)
describe("Composer",()=>{
const wrapper = shallow(<Composition />).dive().find(AdditionalCustomFields).shallow()
it("Describe CustomFieldForm component",()=>{
console.log("sub component========>", wrapper.debug())
})
})
I'm getting this instead of my component structure:-
PASS src/pages/Settings/components/Application/components/CustomFields/components/CustomFieldForm/component/AdditionalCustomFields/AdditionalCustomFields.test.js
● Console
console.log src/pages/Settings/components/Application/components/CustomFields/components/CustomFieldForm/component/AdditionalCustomFields/AdditionalCustomFields.test.js:31
sub component========> <WithStyles(ForwardRef(Grid)) container={true}>
<FormikConnect(FieldArrayInner) name="additionalData" render={[Function: render]} />
</WithStyles(ForwardRef(Grid))>

Related

Testing SVGR as React Component with Jest

Getting a warning when running test on svg component. It's not causing the test to fail but trying to get it cleaned up. Using SVGR to use svg files as react components. I believe the issue is Jest isn't able to see the svgr configuration in webpack, but not sure how to fix it.
Warning
console.error
Warning: <ReactComponent /> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.
at ReactComponent
at Icon (/code/common/javascript/components-2.0/lib/brand/Icon/index.tsx:9:11)
import { SvgIndexable } from "./Icon.types";
import { ReactComponent as ArrowRight } from "./svg/arrow-right.svg";
const iconNames: SvgIndexable = {
"arrow-right": ArrowRight,
}
export default iconNames
index.js
import React from "react";
import className from "classnames";
import { IconTypes } from "./Icon.types";
import iconNames from "./Icon.Components";
import styles from "./Icon.module.scss";
const Icon: React.FC<IconTypes> = (props: IconTypes): JSX.Element| null => {
const { id, name, extraClass, color = "black", size = "medium" } = props;
const iconClasses = className(styles[size], styles[color], extraClass);
const IconComponent = iconNames[name];
if (typeof iconNames[name] !== "undefined") {
return React.createElement(
iconNames[name],
{
id:id,
className:iconClasses,
"data-testid":`test__${id}-icon`,
},
null
);
} else {
return null;
}
};
export default Icon;
jest.config.json
"moduleNameMapper": {
"^#/(.*)$": "<rootDir>/lib/$1",
"components-2.0": "<rootDir>/__mocks__/components-2.0
"\\.(pdf|jpg|jpeg|png|gif|ico|xml|manifestjson|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "identity-obj-proxy",
"\\.svg$": "<rootDir>/__mocks__/components-2.0/svgrMock.js"
},
svgrMock.js
import * as React from "react";
export default "SvgrURL";
export const ReactComponent = "div";

Jest with Apollo Client - Testing React App with calling useQuery inside react hooks context

I have a problem on testing react hooks app with Jest and React-test-renderer. The problem defined when I put useQuery inside of react hooks context file.
I had a similar files following this apollo docs https://www.apollographql.com/docs/react/development-testing/testing/ but only different in calling useQuery in react hooks context file.
CatContext.js
import React, {createContext} from 'react';
import { GET_ALL_CATS } from 'graphqlquery/Queries';
import { useQuery } from '#apollo/client';
export const CatContext = createContext();
export default function CatContextProvider(props) {
const { loading, error, data } = useQuery(GET_ALL_CATS);
return (
<CatContext.Provider value={{loading,error,data}}>
{props.children}
</CatContext.Provider>
);
}
App.js
export function CatList() {
const {loading,error,data} = useContext(CatContext);
if(loading) return <div>Loading...</div>;
if(error) return <div>Error...</div>;
return (
<div>
<div>
{data.cat.name} is a {data.cat.breed}
</div>
</div>
);
}
App.test.js
import React from 'react';
import { MockedProvider } from '#apollo/client/testing';
import TestRenderer from 'react-test-renderer';
import "regenerator-runtime/runtime";
import { CatList } from 'components/CatList';
import { GET_ALL_CATS } from 'graphqlquery/Queries';
const mocks = [
{
request: {
query: GET_ALL_CATS,
},
result: {
data: {
cat: { id: '1', name: 'Buck', breed: 'bulldog' },
}
}
}
]
it('renders without error', () => {
const component = TestRenderer.create(
<MockedProvider mocks={mocks} addTypename={false}>
<CatList />
</MockedProvider>,
);
const tree = component.toJSON();
expect(tree.children).toContain('Loading...');
});
The problem doesn't exists if I call useQuery in App.js, but when I call useQuery inside CatContext, it provides an error : TypeError: Cannot read property 'loading' of undefined.
Any thought why this loading of useQuery that I call from CatContext.js is undefined? and how to fix it?

Client Side Unit Testing Meteor/React w/Enzyme

so i've been stuck for several days on an issue while implementing Unit Testing and Integration testing in a large production application that was built in Meteor/React tech stack. I am using the meteortesting:mocha package as recommended by the meteor documentation and enzyme.
The issue i am having is that i am not really grasping how i can mock the withTracker functionality. I am trying to use our dev database as the source for the test users and mock data. All of the props are generated in the tracker and then sent to the component it wraps. (Code sample below). Another issue i am having is that we are using meteor:universe for i18n internationalization. When mounting the component it shows plain text instead of the translated content. Wondering if there's a work around. Thanks in advance!
Component I am testing:
import React, { useState } from "react";
import ABCComponent from "./ABCComponent";
import XYZ from "./XYZComponent";
import * as ROUTE_CONSTANTS from "../../global/RoutesConstants";
import { withRouter } from "react-router-dom";
import { withTracker } from "meteor/react-meteor-data";
import UserAssessments from "../../collections/UserAssessments";
import moment from "moment-timezone";
import { i18n } from "meteor/universe:i18n";
const SortDashboard = (props) => {
const [isSkillsSort, setIsSkillSort] = useState(true);
return (
<div>
{/* Contains some logic to set 'isSetSkillSort' state true or false (business logic hidden for security purposes*/}
{isSkillsSort ? (
<ABCComponent user={props.user} skillsSorts={props.skillsSorts} employeeList={props.directReportEmp} />
) : (
<XYZComponent
user={props.user}
importanceSorts={props.importanceSorts}
employeeList={props.directReportEmp}
/>
)}
</div>
);
};
const SortDashboardTracker = withTracker((props) => {
if (!props.user) return {};
const abcSubscription = Meteor.subscribe("abcSubscription");
if (abcSubscription.ready()) {
const rawData = UserAssessments.find(
{ "assessor._id": Meteor.user().profile._id },
{ sort: { updatedDate: -1 } }
).fetch();
rawData.forEach((assessment) => {
//Do Something (business logic hidden for security purposes)
});
}
const xyzSubscription = Meteor.subscribe("xyzSubscription");
let directReportEmp = [];
if (xyzSubscription.ready()) {
directReportEmp = Meteor.users.find({ "profile.managerId": Meteor.user().username }).fetch();
}
return { importanceSorts, skillsSorts, directReportEmp };
})(SortDashboard);
export default withRouter(SortDashboardTracker);
My Test:
import {Meteor} from 'meteor/meteor';
import React from 'react';
import chai from 'chai';
import sinon, { mock } from 'sinon'
import {mount, shallow, configure, render} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import {mockManager,mockEmp1,mockEmp2,mockEmp3,mockUser} from '../../mockUsers'
import SortDashboard from '../../../../imports/components/cllWizard/SortDashboard';
import { withRouter, BrowserRouter as Router } from "react-router-dom";
configure({adapter: new Adapter()});
if (Meteor.isClient) {
describe('WizardComponent', ()=> {
//let returnedText
//importing the mock user we created for testing purposes
const currentUser = mockUser
let props = {user: currentUser}
beforeEach(() => {
// now Meteor.user() will return the user we just imported
sinon.stub(Meteor, 'user');
Meteor.user.returns(currentUser);
// needed in methods
sinon.stub(Meteor, 'userId');
Meteor.userId.returns(currentUser._id);
});
//afterEach specifies that we want to restore the user after running the test
afterEach(() => {
Meteor.user.restore();
Meteor.userId.restore();
});
it('CLIENT: should render the Sort Dashboard', () => {
const wrapper = mount(<Router><SortDashboard.WrappedComponent {...props}/></Router>)
console.log(wrapper.debug())
});
});
}
TLDR;
Need to test a client side component that uses withTracker and withRouter
Need to be able to see the translated text from meteor:universe:i18n in the test
Pulling mock data from the db instead of manually creating it.
The issue may very well be my approach and lack of understanding. Please correct me where-ever necessary. Thanks in advance!

Issue with testing Wrapper Query Component

I'm very new to React testing and I'm trying to write Jest/Enzyme Unit tests for the MyReload wrapper component on top of Apollo Query that I have created. This basically adds refetchers to an array (that can be executed at later point of time).
Usage:
<MyReloadQuery id='1234 .....> // do something.. children </MyReloadQuery>
Component:
import React, { Component } from "react";
import PropTypes from "prop-types";
import { Subscribe } from "unstated";
import { Query } from "react-apollo";
import { MyReloadContainer } from "./MyReloadContainer";
export class MyReloadQuery extends Component {
static propTypes = {
children: PropTypes.any
};
componentWillUnmount() {
this.onUnmount();
}
render() {
return (
<Subscribe to={[MyReloadContainer]}>
{refetchers => (
<Query {...this.props}>
{(...args) => {
const { refetch } = args[0];
this.onUnmount = () => {
refetchers.removeRefetcher(refetch);
};
refetchers.addRefetcher(refetch);
return this.props.children(...args);
}}
</Query>
)}
</Subscribe>
);
}
}
I'm very new to React and it's testing and I'm wondering how can one test with dummy data for this one?
Can someone please enlighten me? Any help would be appreciated :pray:

How to assert if an action creator has been called from a redux connected container component

I've tried various ways but I can't seem to find anything about specifically testing if an action creator is called from a component. The hard part seems to be getting enzyme and redux connected containers to work. Below I'm exporting both connected and component class for tests. I tried wrapping the connected one in a provider but then I don't know how to target the textarea from enzyme to trigger the simulated onChange. The below works but I'm not sure if it's the best way of doing this?
Simple container:
I want to assert that onChange will call sendCommandValueChange with the correct value.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { sendCommandValueChange } from 'actions';
export class RobotCommand extends Component {
handleCommandChange(e){
this.props.sendCommandValueChange(e.target.value);
}
render(){
return (
<div>
<textarea
onChange={ e => this.handleCommandChange(e)}
/>
</div>
);
}
}
export default connect(null, { sendCommandValueChange })(RobotCommand);
and here is the test:
import React from 'react';
import { expect } from 'chai';
import sinon from 'sinon';
import { shallow, mount } from 'enzyme';
import { RobotCommand } from './RobotCommand';
describe('RobotCommand', () => {
it('should call sendCommandValueChange action creator on value change', () => {
const props = { sendCommandValueChange: sinon.spy() };
const wrapper = shallow(<RobotCommand {...props} />);
wrapper.find('textarea').simulate('change', {target: {value: 'foo'}});
expect(props.sendCommandValueChange.calledWith('foo')).to.equal(true);
});
});

Resources