Mock http.get method from onClick in react jest-test - reactjs

In jest test i have mock following scenario.
OnClick method I have to call other component method that is promise one
I tried to mock onclick is working. and making call also fine but not able to mock .then return value
File: DashboardChart.js
import getIntentsSince from '../services/getIntentsSince';
initializeCharts() {
// I want to mock this. I am not able to get .then response value
getIntentsSince(this.state.nowDateTime, DateUtil.getPreviousDayTS(this.state.nowDateTime))
.then((topIntents) => {
// I have to cover the code. Which is here
})
}
getChart(){
this.setState({it has some code})
this.initializeCharts()
}
render(){
return (
<button onClick={this.getChart}> get chart</button>
)
}
File: getIntentsSince.js
import HttpClient from 'custom-http-client';
const client = new HttpClient();
const getIntentsSince = (currentTime, fromIntervalTime) => {
return client.get(`url`).then((data) => {
return data;
})
};
export default getIntentsSince;
This is how i have tried
import React from 'react';
import { shallow, mount } from 'enzyme';
import Dashboard from '../../src/components/DashboardChart';
import getIntentsSince from '../../src/services/getIntentsSince'
import mockHttpClient from 'axp-http-client';
const client = new mockHttpClient();
import mockData from './Intents.json'
describe('Dashboard Page test cases', () => {
let mockValue = jest.mock('../../src/services/getIntentsSince', () => new Promise(resolve => resolve({getIntentsSince: () => {return mockData}})))
beforeAll(()=> {
dashboardMock = mount(<DashboardChart getIntentsSince={mockValue}/>);
});

Here is the solution based on the code you provide.
Folder sturcture:
.
├── DashboardChart.spec.tsx
├── DashboardChart.tsx
├── custom-http-client.ts
└── getIntentsSince.ts
DashboardChart.tsx:
import React, { Component } from 'react';
import getIntentsSince from './getIntentsSince';
const DateUtil = {
getPreviousDayTS(datetime) {
return datetime;
}
};
interface IDashboardChartState {
nowDateTime: string;
}
class DashboardChart extends Component<{}, IDashboardChartState> {
constructor(props) {
super(props);
this.state = {
nowDateTime: '2019'
};
this.getChart = this.getChart.bind(this);
}
public initializeCharts() {
return getIntentsSince(this.state.nowDateTime, DateUtil.getPreviousDayTS(this.state.nowDateTime)).then(
topIntents => {
// I have to cover the code. Which is here
console.log(topIntents);
}
);
}
public getChart() {
this.setState({});
this.initializeCharts();
}
public render() {
return <button onClick={this.getChart}> get chart</button>;
}
}
export default DashboardChart;
getIntentsSince.ts:
import HttpClient from './custom-http-client';
const client = new HttpClient();
const getIntentsSince = (currentTime, fromIntervalTime) => {
return client.get(`url`).then(data => {
return data;
});
};
export default getIntentsSince;
custom-http-client.ts:
export default class HttpClient {
public async get(url) {
return 'real data';
}
}
DashboardChart.spec.tsx:
import React from 'react';
import { mount, ReactWrapper } from 'enzyme';
import DashboardChart from './DashboardChart';
import getIntentsSince from './getIntentsSince';
jest.mock('./getIntentsSince.ts', () => jest.fn());
describe('Dashboard Page test cases', () => {
let wrapper: ReactWrapper;
beforeAll(() => {
wrapper = mount(<DashboardChart />);
});
afterEach(() => {
jest.resetAllMocks();
jest.restoreAllMocks();
});
it('should get indents since correctly', async () => {
const mockedResponse = 'mocked response';
(getIntentsSince as jest.MockedFunction<typeof getIntentsSince>).mockResolvedValueOnce(mockedResponse);
const logSpy = jest.spyOn(console, 'log');
const actualValue = await (wrapper.instance() as any).initializeCharts();
expect(actualValue).toBeUndefined();
expect(logSpy).toBeCalledWith(mockedResponse);
expect(getIntentsSince).toBeCalledWith('2019', '2019');
});
});
Unit test result with coverage report:
PASS src/stackoverflow/55789099/DashboardChart.spec.tsx (6.208s)
Dashboard Page test cases
✓ should get indents since correctly (14ms)
console.log node_modules/jest-mock/build/index.js:860
mocked response
--------------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
--------------------|----------|----------|----------|----------|-------------------|
All files | 89.47 | 100 | 85.71 | 88.89 | |
DashboardChart.tsx | 89.47 | 100 | 85.71 | 88.89 | 33,34 |
--------------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 7.731s, estimated 9s
HTML coverage report:
Here is the completed demo: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/55789099

Related

React testing axios get request in componentDidMount using jest

I am new to React testing and I am trying to test a get request which is coming from a backend call using axios.
The component:
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
stockData: [],
}
}
componentDidMount() {
axios.get("http://localhost:8080/stocks")
.then(response => {
this.setState({
stockData: response.data
})
})
}
render() {
return (
<ChildComponent stockData={this.state.stockData}/>
)
}
}
The data fetched from the call is something like the following:
stockData: [
{
"ticker": "AAPL",
"name": "Apple Inc",
"priceChanges": {
"daily": 1.55,
"weekly": -3.55,
"monthly": -20.00
},
"financialData": {
"roa": 5.74,
"roe": 20.07,
"market_cap": "1.2T"
}
},
{
"ticker": "MSFT",
"name": "Microsoft Corporation",
"priceChanges": {
"daily": 4.35,
"weekly": 1.25,
"monthly": -22.05
},
"financialData": {
"roa": 8.73,
"roe": 15.07,
"market_cap": "1.3T"
}
}
//and many other similar objects
]
I have read that I should not really use the real get request and instead use some "mock" data but don't have an idea how to implement it. I have tried the following, but I am not sure if it is the right way to do this. Also, I am getting an error: TypeError: Cannot read property 'then' of undefined
test('should fetch company', () => {
const wrapper = shallow(<ParentComponent/>);
const resp = {stockData: [
{
"ticker": "AAPL",
"name": "Apple Inc",
"priceChanges": {
"daily": 1.55,
"weekly": -3.55,
"monthly": -20.00
},
"financialData": {
"roa": 5.74,
"roe": 20.07,
"market_cap": "1.2T"
}
}
};
wrapper.instance().componentDidMount().then(resp => {
expect(wrapper.state('stockData')).toContain(resp.stockData);
});
});
You can use jest.spyOn(object, methodName) to mock axios.get method and its resolved value. Since axios.get is an asynchronous operation, We need to wait until it is done.
E.g.
parent.jsx:
import React from 'react';
import { ChildComponent } from './child';
import axios from 'axios';
export class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
stockData: [],
};
}
componentDidMount() {
axios.get('http://localhost:8080/stocks').then((response) => {
this.setState({ stockData: response.data });
});
}
render() {
return <ChildComponent stockData={this.state.stockData} />;
}
}
child.jsx:
import React, { Component } from 'react';
export class ChildComponent extends Component {
render() {
return <div></div>;
}
}
parent.test.jsx:
import { ParentComponent } from './parent';
import { shallow } from 'enzyme';
import axios from 'axios';
import React from 'react';
import { act } from 'react-dom/test-utils';
const whenStable = async () => {
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
};
describe('61465031', () => {
it('should pass', async () => {
const mResponse = { data: ['a', 'b'] };
const getSpy = jest.spyOn(axios, 'get').mockResolvedValueOnce(mResponse);
const wrapper = shallow(<ParentComponent></ParentComponent>);
await whenStable();
expect(wrapper.find('ChildComponent').prop('stockData')).toEqual(['a', 'b']);
getSpy.mockRestore();
});
});
unit test results with coverage report:
PASS stackoverflow/61465031/parent.test.jsx (11.345s)
61465031
✓ should pass (20ms)
------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------|---------|----------|---------|---------|-------------------
All files | 95.45 | 100 | 85.71 | 94.12 |
child.jsx | 85.71 | 100 | 50 | 80 | 5
parent.jsx | 100 | 100 | 100 | 100 |
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 12.876s
source code: https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/61465031

React Hooks jest testing - method is not a function

I'm getting fed up with trying to test hooks but I feel so close with this approach. Here me out.
I've got this test running and it gives me this error:
'TypeError: handleCount is not a function'
describe("<Content />", () => {
const setCount = jest.fn();
let activeTab = 'Year';
test("Ensure that handleCount is fired if activeTab is the type year", () => {
handleYearTab(setCount, activeTab);
});
});
So this makes sense but I'm not sure how I can mock the method that it is complaining about. this is my component that I'm trying to test:
/**
* Get new count from getTotalAttendances
* #param dates | New date picked by the user
* #param setCount | Hook function
* #param activeTab | Type of tab
*/
function handleCount(
dates: object,
setCount: Function,
activeTab?: string,
) {
const totalCount = new GetTotal(dates, activeTab);
setCount(totalCount.totalAttendances());
}
/**
* Handle count for the year tab.
* #param setCount | Hook function
* #param activeTab | Type of tab
*/
export function handleYearTab(
setCount: Function,
activeTab: string,
) {
if (activeTab === 'Year') {
handleCount(new Date(), setCount, activeTab);
}
}
const Content: FC<Props> = ({ activeTab }) => {
const [count, setCount] = useState<number>(0);
useEffect(() => {
handleYearTab(setCount, activeTab);
});
return (
<Container>
<TotalAttendences count={count} />
</Container>
);
}
export default Content;
I'm really curious how you would go about mocking the handleCount method.
Here is the unit test solution using jestjs and react-dom/test-utils:
index.tsx:
import React, { FC, useState, useEffect } from 'react';
import { GetTotal } from './getTotal';
interface Props {
activeTab: string;
}
function handleCount(dates: object, setCount: Function, activeTab?: string) {
const totalCount = new GetTotal(dates, activeTab);
setCount(totalCount.totalAttendances());
}
export function handleYearTab(setCount: Function, activeTab: string) {
if (activeTab === 'Year') {
handleCount(new Date(), setCount, activeTab);
}
}
const Content: FC<Props> = ({ activeTab }) => {
const [count, setCount] = useState<number>(0);
useEffect(() => {
handleYearTab(setCount, activeTab);
});
return <div>{count}</div>;
};
export default Content;
getTotal.ts:
export class GetTotal {
constructor(dates, activeTab) {}
public totalAttendances(): number {
return 1;
}
}
index.test.tsx:
import Content from './';
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { act } from 'react-dom/test-utils';
import { GetTotal } from './getTotal';
describe('60638277', () => {
let container;
beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
});
afterEach(() => {
unmountComponentAtNode(container);
container.remove();
container = null;
});
it('should handle year tab', async () => {
const totalAttendancesSpy = jest.spyOn(GetTotal.prototype, 'totalAttendances').mockReturnValue(100);
const mProps = { activeTab: 'Year' };
await act(async () => {
render(<Content {...mProps}></Content>, container);
});
expect(container.querySelector('div').textContent).toBe('100');
expect(totalAttendancesSpy).toBeCalled();
totalAttendancesSpy.mockRestore();
});
it('should render initial count', async () => {
const mProps = { activeTab: '' };
await act(async () => {
render(<Content {...mProps}></Content>, container);
});
expect(container.querySelector('div').textContent).toBe('0');
});
});
unit test results with coverage report:
PASS stackoverflow/60638277/index.test.tsx (9.331s)
60638277
✓ should handle year tab (32ms)
✓ should render initial count (11ms)
-------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------|---------|----------|---------|---------|-------------------
All files | 95.24 | 100 | 85.71 | 94.12 |
getTotal.ts | 80 | 100 | 66.67 | 75 | 4
index.tsx | 100 | 100 | 100 | 100 |
-------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 10.691s
source code: https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/60638277

How to mock/spy addEventListener method which is called on ref in ReactJS?

I am doing snapshot testing for one component which has ref on its div. The component looks like -
import React, { PureComponent } from 'react';
class SearchFlightBuilder extends PureComponent {
scrollRef = React.createRef();
state = {
loading: true,
error: false,
filteredList: [],
pageIndex: 0,
scrollCalled: false,
};
handleScroll = (event) => {
// make sure scroll should be called once
if ((this.scrollRef.current.scrollTop + this.scrollRef.current.clientHeight >= this.scrollRef.current.scrollHeight) && !this.state.scrollCalled) {
this.setState({
pageIndex: this.state.pageIndex + 1
});
this.setState({scrollCalled: true});
}
};
componentDidMount = () => {
this.scrollRef.current.addEventListener('scroll', this.handleScroll);
};
removeScrollEvent = () => {
this.scrollRef.current.removeEventListener('scroll', this.handleScroll);
};
render() {
return (
<div className={c('Search-flight-builder')} ref={this.scrollRef}>
<p>Hello</P
</div>
);
}
};
export default SearchFlightBuilder;
And testing file looks like this -
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import SearchFlightBuilder from './SearchFlightBuilder';
configure({ adapter: new Adapter() });
const testFlightBuilder = () => <SearchFlightBuilder />;
describe('SearchFlightBuilder', () => {
it('should render correctly', () => {
const component = shallow(<SearchFlightBuilder />);
expect(component).toMatchSnapshot();
});
});
When I am running the tests, I am getting this error -
TypeError: Cannot read property 'addEventListener' of null. I tried various approaches, but none of the approach works. Please help me here. I am using enzyme library here.
Here is my unit test strategy:
index.tsx:
import React, { PureComponent } from 'react';
class SearchFlightBuilder extends PureComponent {
scrollRef: any = React.createRef();
state = {
loading: true,
error: false,
filteredList: [],
pageIndex: 0,
scrollCalled: false
};
handleScroll = event => {
// make sure scroll should be called once
if (
this.scrollRef.current.scrollTop + this.scrollRef.current.clientHeight >= this.scrollRef.current.scrollHeight &&
!this.state.scrollCalled
) {
this.setState({
pageIndex: this.state.pageIndex + 1
});
this.setState({ scrollCalled: true });
}
};
componentDidMount = () => {
this.scrollRef.current.addEventListener('scroll', this.handleScroll);
};
removeScrollEvent = () => {
this.scrollRef.current.removeEventListener('scroll', this.handleScroll);
};
render() {
return (
<div className="Search-flight-builder" ref={this.scrollRef}>
<p>Hello</p>
</div>
);
}
}
export default SearchFlightBuilder;
Since clientHeight and scrollHeight properties are read-only, so they need to be mocked using Object.defineProperty.
index.spec.tsx:
import React from 'react';
import { shallow } from 'enzyme';
import SearchFlightBuilder from './';
describe('SearchFlightBuilder', () => {
afterEach(() => {
jest.restoreAllMocks();
});
it('should handle scroll, pageindex + 1', () => {
const mDiv = document.createElement('div');
const events = {};
const addEventListenerSpy = jest.spyOn(mDiv, 'addEventListener').mockImplementation((event, handler) => {
events[event] = handler;
});
mDiv.scrollTop = 1;
Object.defineProperty(mDiv, 'clientHeight', { value: 1 });
Object.defineProperty(mDiv, 'scrollHeight', { value: 1 });
const mRef = { current: mDiv };
const createRefSpy = jest.spyOn(React, 'createRef').mockReturnValueOnce(mRef);
const component = shallow(<SearchFlightBuilder />);
expect(createRefSpy).toBeCalledTimes(1);
expect(addEventListenerSpy).toBeCalledWith('scroll', component.instance()['handleScroll']);
events['scroll']();
expect(component.state('pageIndex')).toBe(1);
expect(component.state('scrollCalled')).toBeTruthy();
});
});
Unit test result with coverage report:
PASS src/stackoverflow/57943619/index.spec.tsx (8.618s)
SearchFlightBuilder
✓ should handle scroll, pageindex + 1 (15ms)
-----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files | 94.44 | 85.71 | 80 | 93.75 | |
index.tsx | 94.44 | 85.71 | 80 | 93.75 | 32 |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 9.916s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/57943619

How to test redirects in ComponentWillMount in enzyme/jest

I am new to testing in Enzyme and Jest.
I want to test my ComponentWillMount method, whether certain redirect will happen or not.
Here is the code of my component:
class ActivationSF extends Component {
constructor(props) {
super(props);
this.className = 'ActivationSF.js'
this.state = {
messages: null,
}
}
render() {
return (
<ActivationUI
context={this.props.context}
messages={this.state.messages}
/>
);
}
componentWillMount() {
let context = this.props.context
if(!context.userInfo){
window.location.replace('/identify')
}
let externalLP = ExternalLandingPageUtil.getExternalLandingPageUrl(context);
if (externalLP) {
window.location.replace(`${externalLP}`);
return;
}
if (context.userInfo)
{
window.location = '/store'
}
}
componentDidMount() {
document.body.classList.add('sdp')
}
Here is a unit test strategy:
index.tsx:
import React, { Component } from 'react';
import { ExternalLandingPageUtil } from './ExternalLandingPageUtil';
import { ActivationUI } from './ActivationUI';
export class ActivationSF extends Component<any, any> {
public className: string;
constructor(props) {
super(props);
this.className = 'ActivationSF.js';
this.state = {
messages: null
};
}
render() {
return <ActivationUI context={this.props.context} messages={this.state.messages} />;
}
componentWillMount() {
let context = this.props.context;
if (!context.userInfo) {
window.location.replace('/identify');
}
let externalLP = ExternalLandingPageUtil.getExternalLandingPageUrl(context);
if (externalLP) {
window.location.replace(`${externalLP}`);
return;
}
if (context.userInfo) {
window.location.replace('/store');
}
}
componentDidMount() {
document.body.classList.add('sdp');
}
}
ActivationUI.tsx:
import React from 'react';
export const ActivationUI = ({ context, messages }) => <div>ActivationUI</div>;
ExternalLandingPageUtil.ts:
export const ExternalLandingPageUtil = {
getExternalLandingPageUrl(context) {
return context.externalLP;
}
};
index.spec.tsx:
import React from 'react';
import { ActivationSF } from './';
import { ExternalLandingPageUtil } from './ExternalLandingPageUtil';
import { shallow } from 'enzyme';
window.location.replace = jest.fn();
describe('ActivationSF', () => {
afterEach(() => {
jest.resetAllMocks();
});
test('should redirect to /identify', () => {
const mProps = { context: {} };
const wrapper = shallow(<ActivationSF {...mProps}></ActivationSF>);
expect(window.location.replace).toBeCalledWith('/identify');
});
test('should redirect to external IP address', () => {
const spy = jest.spyOn(ExternalLandingPageUtil, 'getExternalLandingPageUrl');
const mProps = { context: { userInfo: {}, externalLP: '10.0.0.1' } };
const wrapper = shallow(<ActivationSF {...mProps}></ActivationSF>);
expect(window.location.replace).toBeCalledWith('10.0.0.1');
expect(spy).toBeCalledWith(mProps.context);
});
test('should redirect to /store', () => {
const mProps = { context: { userInfo: {} } };
const wrapper = shallow(<ActivationSF {...mProps}></ActivationSF>);
expect(window.location.replace).toBeCalledWith('/store');
});
test('should render correctly', () => {
const mProps = { context: {} };
const addSpy = jest.spyOn(document.body.classList, 'add');
const wrapper = shallow(<ActivationSF {...mProps}></ActivationSF>);
expect(wrapper.prop('context')).toEqual(mProps.context);
expect(wrapper.state('messages')).toBeNull();
expect(addSpy).toBeCalledWith('sdp');
addSpy.mockRestore();
});
});
Unit test result with 100% coverage for ActivationSF component.
PASS src/stackoverflow/57673447/index.spec.tsx (12.286s)
ActivationSF
✓ should redirect to /identify (14ms)
✓ should redirect to external IP address (2ms)
✓ should redirect to /store (1ms)
✓ should render correctly (2ms)
----------------------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------------------------|----------|----------|----------|----------|-------------------|
All files | 90.32 | 100 | 85.71 | 100 | |
ActivationUI.tsx | 40 | 100 | 0 | 100 | |
ExternalLandingPageUtil.ts | 100 | 100 | 100 | 100 | |
index.tsx | 100 | 100 | 100 | 100 | |
----------------------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 4 passed, 4 total
Snapshots: 0 total
Time: 14.412s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/57673447

After Simulate('change') state is not updated

I've got a search filter component with an input inside it, and it's connected to redux.
class SearchFilter extends PureComponent {
constructor (props) {
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
this.state = {
keyword: props.searchKeyword
};
}
handleInputChange (e) {
this.setState({keyword: e.target.value});
this.props.dispatch(SetFiltersValue(...);
}
render () {
const {keyword} = this.state;
return (
<div className="search-w bp3-input-group">
<span className="bp3-icon bp3-icon-search"/>
<input className="bp3-input" value={keyword} type="text" placeholder="Search input" dir="auto" onChange={this.handleInputChange} />
</div>
);
}
}
const mapStateToProps = (_, ownParams) => {...};
export default connect(mapStateToProps)(SearchFilter);
I wrote a test in jest and enzyme to test state updates when user enters a new value
import React from "react";
import SearchFilter from "../../dev/components/shared/searchFilter";
import {shallow, mount} from "enzyme";
import configureStore from "redux-mock-store";
describe("Testing Search filter", () => {
const mockStore = configureStore(),
initialStoreState = {
filtersParams: {}
};
let store;
beforeEach(() => {
store = mockStore(initialStoreState);
});
it("Update search field value when user enters a value", () => {
const wrapper = shallow(<SearchFilter store={store}/>).dive(),
searchInput = wrapper.find("input.bp3-input").first();
expect(searchInput).toBeDefined();
const mockedEvent = {
preventDefault () {},
target: { value: "foo" }
};
expect(wrapper.state("keyword")).toEqual("");
searchInput.simulate("change", mockedEvent);
wrapper.update();
expect(wrapper.state("keyword")).toEqual("foo");
});
});
The problem is that state does't update after simulating change, and test always fails.
How can I fix this or is there other way to test state updates?
Comment is cheap, show you the code:
index.tsx, the React Component to be tested:
import React, { PureComponent } from 'react';
import { connect, DispatchProp } from 'react-redux';
import { SetFiltersValue } from './actionCreators';
interface ISearchFilterStateProps {
searchKeyword: string;
}
interface ISearchFilterState {
keyword: string;
}
type Props = ISearchFilterStateProps & DispatchProp;
class SearchFilter extends PureComponent<Props, ISearchFilterState> {
constructor(props: Props) {
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
this.state = {
keyword: props.searchKeyword
};
}
public handleInputChange(e: React.ChangeEvent<HTMLInputElement>) {
this.setState({ keyword: e.target.value });
this.props.dispatch(SetFiltersValue());
}
public render() {
const { keyword } = this.state;
return (
<div className="search-w bp3-input-group">
<span className="bp3-icon bp3-icon-search" />
<input
className="bp3-input"
value={keyword}
type="text"
placeholder="Search input"
dir="auto"
onChange={this.handleInputChange}
/>
</div>
);
}
}
const mapStateToProps = (_, ownParams) => {
return { searchKeyword: '' };
};
export default connect(mapStateToProps)(SearchFilter);
actionCreators.ts:
export const SetFiltersValue = () => ({ type: 'SET_FILTER' });
Unit test:
import React from 'react';
import { shallow } from 'enzyme';
import configureStore from 'redux-mock-store';
import SearchFilter from './';
import { SetFiltersValue } from './actionCreators';
const initialState = { filtersParams: {} };
type State = typeof initialState;
const mockStore = configureStore<State>();
describe('SearchFilter', () => {
let store;
beforeEach(() => {
store = mockStore(initialState);
});
it('t1', () => {
const searchFilter = shallow(<SearchFilter store={store}></SearchFilter>).dive();
const searchInputWrapper = searchFilter.dive();
const searchInput = searchInputWrapper.find('input.bp3-input').first();
expect(searchInputWrapper.state('keyword')).toBe('');
const mockedEvent = {
preventDefault: jest.fn(),
target: { value: 'foo' }
};
searchInput.simulate('change', mockedEvent);
expect(searchInputWrapper.state('keyword')).toBe('foo');
expect(store.getActions()).toEqual([SetFiltersValue()]);
expect(searchInputWrapper.html()).toMatchSnapshot();
});
});
Unit test result with 100% coverage:
PASS src/stackoverflow/54587960/index.spec.tsx
SearchFilter
✓ t1 (28ms)
› 1 snapshot written.
-------------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-------------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
actionCreators.ts | 100 | 100 | 100 | 100 | |
index.tsx | 100 | 100 | 100 | 100 | |
-------------------|----------|----------|----------|----------|-------------------|
Snapshot Summary
› 1 snapshot written from 1 test suite.
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 1 written, 1 total
Time: 4.367s, estimated 5s
React Component Snapshot:
// Jest Snapshot v1
exports[`SearchFilter t1 1`] = `"<div class=\\"search-w bp3-input-group\\"><span class=\\"bp3-icon bp3-icon-search\\"></span><input type=\\"text\\" class=\\"bp3-input\\" value=\\"foo\\" placeholder=\\"Search input\\" dir=\\"auto\\"/></div>"`;
Here is the completed demo: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/54587960

Resources