Enzyme shallow dive fails with connected component - reactjs

I try to test my connect component. Running this test:
import React from 'react';
import { shallow } from 'enzyme';
import Dashboard from './Dashboard';
describe('Dashboard', () => {
test('should render correctly according to the snapshot', () => {
const wrapper = shallow(<Dashboard />).dive();
expect(wrapper).toMatchSnapshot();
});
});
According to this comment this should work but fails:
node_modules/subscriptions-transport-ws/node_modules/iterall/index.mjs:84
export var $$iterator = SYMBOL_ITERATOR || '##iterator'
^^^^^^
SyntaxError: Unexpected token export
at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/ScriptTransformer.js:289:17)
at Object.<anonymous> (node_modules/subscriptions-transport-ws/dist/utils/empty-iterable.js:3:17)
at Object.<anonymous> (node_modules/subscriptions-transport-ws/dist/server.js:8:24)
The dashboard is connected with react-redux's connnect HOC:
const mapStateToProps = (state) => ({
apolloLink: state.apollo.apolloLink,
});
export default connect(mapStateToProps)(Dashboard);
Am I missing something?

When testing a component that uses redux, you need to mock your store and provide it to your component before testing it. You can use the "redux-mock-store" npm package to do so.
For Example:
import React from 'react';
import { shallow } from 'enzyme';
import Dashboard from './Dashboard';
import configureStore from 'redux-mock-store'
describe('Dashboard', () => {
initialState = { apollo: { apolloLink: 'test value goes here' } }
let store, wrapper;
beforeEach(() => {
store = mockStore(initialState)
wrapper = shallow(<Dashboard store={store} />).dive()
})
it("Should render correctly according to snapshot", () => {
let tree = wrapper.toJSON();
expect(tree).toMatchSnapshot();
});
});

Related

Consoling shallow(<component />) results in ShallowWrapper {}

this is my collegeName.test.js
import React from 'react';
import Enzyme, { shallow, mount } from 'enzyme';
import PersonalProfile from '../../../components/Profile/Tabs/Personal';
import Adapter from "enzyme-adapter-react-16";
import { Provider } from "react-redux";
import configureMockStore from "redux-mock-store";
import configureStore from "../../../redux/configureStore";
import { fetchData, mutateData } from "../../../utils/graphqlUtility";
Enzyme.configure({ adapter: new Adapter() })
const store = configureStore();
//const store = mockStore({});
jest.mock('../../../utils/graphqlUtility', () => {
return {
A:"hihihi"
};
});
describe('Personal Profile', () => {
test('renders', () => {
const wrapper = shallow(
<Provider store={store}>
<PersonalProfile />
</Provider>
);
console.log(wrapper)
let tree = wrapper.toJSON();
expect(tree).toMatchSnapshot();
//<div className="row pad"></div>
//expect(wrapper.contains(<label>Bond Expiration Date</label>)).to.equal(true);
//const paragraph = wrapper.find('div')
//console.log("dsdsds",paragraph)
//expect(paragraph).toHaveLength(1)
});
});
In this file, I am shallowing personalprofile component and this personal profile component calls some methods of graphqlutility file so I mocked graphqlutility file. And then while I am consoling the wrapper its showing me like this in console ShallowWrapper {}.I don't know why the console is showing empty?
I have also attached the screenshot of the console. Can anybody help me with this ?
Use the enzyme's debug() function:
console.log(wrapper.debug());

Testing custom hook: Invariant Violation: could not find react-redux context value; please ensure the component is wrapped in a <Provider>

I got a custom hook which I want to test. It receives a redux store dispatch function and returns a function. In order to get the result I'm trying to do:
const { result } = renderHook(() => { useSaveAuthenticationDataToStorages(useDispatch())});
However, I get an error:
Invariant Violation: could not find react-redux context value; please ensure the component is wrapped in a
It happens because of the useDispatch and that there is no store connected. However, I don't have any component here to wrap with a provider.. I just need to test the hook which is simply saving data to a store.
How can I fix it?
The react hooks testing library docs go more into depth on this. However, what we essentially are missing is the provider which we can obtain by creating a wrapper. First we declare a component which will be our provider:
import { Provider } from 'react-redux'
const ReduxProvider = ({ children, reduxStore }) => (
<Provider store={reduxStore}>{children}</Provider>
)
then in our test we call
test("...", () => {
const store = configureStore();
const wrapper = ({ children }) => (
<ReduxProvider reduxStore={store}>{children}</ReduxProvider>
);
const { result } = renderHook(() => {
useSaveAuthenticationDataToStorages(useDispatch());
}, { wrapper });
// ... Rest of the logic
});
This is probably a late answer but you can also use this in your test
jest.mock('react-redux', () => {
const ActualReactRedux = jest.requireActual('react-redux');
return {
...ActualReactRedux,
useSelector: jest.fn().mockImplementation(() => {
return mockState;
}),
};
});
This issues is related your test file. You have to declarer provider and store in your test file.
Update or replace your app.test.tsx by below code
NB: Don't forget to install redux-mock-store if you don't have already.
import React from 'react';
import { render } from '#testing-library/react';
import App from './App';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
describe('With React Testing Library', () => {
const initialState = { output: 10 };
const mockStore = configureStore();
let store;
it('Shows "Hello world!"', () => {
store = mockStore(initialState);
const { getByText } = render(
<Provider store={store}>
<App />
</Provider>
);
expect(getByText('Hello World!')).not.toBeNull();
});
});
I got this solution after searching 1 hours.
Thanks a lot to OSTE
Original Solution: Github issues/8145 and solution link
With this solution if you get error like TypeError: window.matchMedia is not a function then solve by this way. add those line to your setupTests.ts file. Original solution link stackoverflow.com/a/64872224/5404861
global.matchMedia = global.matchMedia || function () {
return {
addListener: jest.fn(),
removeListener: jest.fn(),
};
};
I think you can create test-utils.[j|t]s(?x), or whatever you set the name of the file to, like this:
https://github.com/hafidzamr/nextjs-ts-redux-toolkit-quickstart/blob/main/__tests__/test-utils.tsx
//root(or wherever your the file)/test-utils.tsx
import React from 'react';
import { render, RenderOptions } from '#testing-library/react';
import { Provider } from 'react-redux';
// Import your store
import { store } from '#/store';
const Wrapper: React.FC = ({ children }) => <Provider store={store}>{children}</Provider>;
const customRender = (ui: React.ReactElement, options?: Omit<RenderOptions, 'wrapper'>) => render(ui, { wrapper: Wrapper, ...options });
// re-export everything
export * from '#testing-library/react';
// override render method
export { customRender as render };
Use it like this:
https://github.com/hafidzamr/nextjs-ts-redux-toolkit-quickstart/blob/main/__tests__/pages/index.test.tsx
//__tests__/pages/index.test.tsx
import React from 'react';
import { render, screen } from '../test-utils';
import Home from '#/pages/index';
describe('Home Pages', () => {
test('Should be render', () => {
render(<Home />);
const getAText = screen.getByTestId('welcome');
expect(getAText).toBeInTheDocument();
});
});
Works for me.
screenshot work
BTW, if you place the test-utils.[j|t]s(?x) or whatever you set the name file place on the directory __test__, don't forget to ignore it on jest.config.js.
//jest.config.js
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/', '<rootDir>/__tests__/test-utils.tsx'],
repo: https://github.com/hafidzamr/nextjs-ts-redux-toolkit-quickstart

Props aren't passing inside component in test cases written with Jest and Enzyme

This is my test case
import React from 'react';
import { mount } from 'enzyme';
import CustomForm from '../index';
describe('Custom Form mount testing', () => {
let props;
let mountedCustomForm;
beforeEach(() => {
props = {
nav_module_id: 'null',
};
mountedCustomForm = undefined;
});
const customform = () => {
if (!mountedCustomForm) {
mountedCustomForm = mount(
<CustomForm {...props} />
);
}
return mountedCustomForm;
};
it('always renders a div', () => {
const divs = customform().find('div');
console.log(divs);
});
});
Whenever I run the test case using yarn test. It gives the following error TypeError: Cannot read property 'nav_module_id' of undefined.
I have already placed console at multiple places in order to see the value of props. It is getting set. But it couldn't just pass through the components and give the error mentioned above.
Any help would be appreciated been stuck for almost 2-3 days now.
You have to wrap the component that you want to test in beforeEach method such that it becomes available for all the 'it' blocks, and also you have to take the mocked props that you think you are getting into the original component.
import React from 'react'
import {expect} from 'chai'
import {shallow} from 'enzyme'
import sinon from 'sinon'
import {Map} from 'immutable'
import {ClusterToggle} from '../../../src/MapView/components/ClusterToggle'
describe('component tests for ClusterToggle', () => {
let dummydata
let wrapper
let props
beforeEach(() => {
dummydata = {
showClusters: true,
toggleClustering: () => {}
}
wrapper = shallow(<ClusterToggle {...dummydata} />)
props = wrapper.props()
})
describe(`ClusterToggle component tests`, () => {
it(`1. makes sure that component exists`, () => {
expect(wrapper).to.exist
})
it('2. makes sure that cluster toggle comp has input and label', () => {
expect(wrapper.find('input').length).to.eql(1)
expect(wrapper.find('label').length).to.eql(1)
})
it('3. simulating onChange for the input element', () => {
const spy = sinon.spy()
const hct = sinon.spy()
hct(wrapper.props(), 'toggleClustering')
spy(wrapper.instance(), 'handleClusterToggle')
wrapper.find('input').simulate('change')
expect(spy.calledOnce).to.eql(true)
expect(hct.calledOnce).to.eql(true)
})
})
})

Why enzyme tests did not work in React.js?

I am using Enzyme tests within Create-React-App. In shallow rendering it works fine, but mount rendering throws error:
TypeError: Cannot read property 'favorites' of undefined
Test file looks like this:
import React, { Component } from "react";
import configureMockStore from "redux-mock-store";
import { shallow, mount } from "enzyme";
import { Provider } from "react-redux";
import Favorites from "../Landing/Favorites";
const mockStore = configureMockStore();
const store = mockStore({});
function setup() {
const props = {
favorites: 42
};
const wrapper = mount(
<Provider store={store}>
<Favorites {...props} />
</Provider>
);
return {
props,
wrapper
};
}
describe("Favorites component", () => {
const { wrapper } = setup();
it("should render list of favorites cards", () => {
expect(wrapper.prop("favorites")).toEqual(42);
});
});
Why did it happen?
.prop works different in mount and shallow. You can check the docs.
http://airbnb.io/enzyme/docs/api/ReactWrapper/prop.html
http://airbnb.io/enzyme/docs/api/ShallowWrapper/prop.html
When using mount, you can directly render Favorites component.
mount(<Favorites {...props} />)

Jest / React / Redux - MapDispatchToProps Undefined

I am trying to learn React w/ Jest / Enzyme.
I have a component that receives 2 props -
loadTenantListAction,
filterTenantListAction,
These props are passed in via mapDispatchToProps -
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import {
loadTenantListAction,
filterTenantListAction,
} from '../../store/actions';
import TenantList from './TenantList';
const mapStateToProps = tenants => ({ tenants });
const mapDispatchToProps = {
loadTenantListAction,
filterTenantListAction,
};
export default withRouter(
connect(mapStateToProps, mapDispatchToProps)(TenantList)
);
I have declared propTypes in my component as such -
import React, { Component } from 'react';
import PropTypes from 'prop-types';
export default class TenantList extends Component {
static propTypes = {
loadTenantListAction: PropTypes.func.isRequired,
filterTenantListAction: PropTypes.func.isRequired,
};
render() {
return <p>Foo</p>;
}
}
My unit test is failing now showing that these props are marked as required, but are undefined. I expect this, as I am not passing them into my test -
import React from 'react';
import { shallow } from 'enzyme';
import TenantListContainer from '../../../src/containers/TenantList';
import TenantList from '../../../src/containers/TenantList/TenantList';
describe('<TenantList />', () => {
it('should render the TenantList Component', () => {
const wrapper = shallow(<TenantListContainer />);
expect(wrapper.find(<TenantList />)).toBeTruthy();
});
});
I can pass the test doing something like
expect(
wrapper.find(
<TenantList
loadTenantListAction={() => {}}
filterTenantListAction={() => {}}
/>
)
).toBeTruthy();
But that does not seem right at all, nor do I expect to be able to write useful tests by carrying on like that.
How should I be handling props passed in via mapDispatchToProps?
You can pass props directly to your component in shallow method.
describe('<TenantList />', () => {
const props = {
loadTenantListAction: () => {}, // or you can use any spy if you want to check if it's called or not
filterTenantListAction () => {},
}
it('should render the TenantList Component', () => {
const wrapper = shallow(<TenantListContainer {...props} />);
expect(wrapper.find(<TenantList />)).toBeTruthy();
});
});

Resources