I have a Helper.js file with several helper functions as below that is being used in different components.
export function buildOptions(elem) {
var oList=[];
for (var i=0; i < field.length; i++) {
oList.push (
<option value={options[i]["id"]}>
{options[i][elem]}
</option>
)
}
return oList;
}
export function B(){
.....
}
Here is a component which makes use of the function defined in Helper.js file. I am writing tests for the component and I would like to mock the external function being called here.
import React from 'react';
import ReactDOM from 'react-dom';
import { buildOptions, A} from './Helper.js';
class DemoComponent extends React.Component {
constructor(props) {
super(props);
}
add(e, index) {
....
}
render() {
var o_list=buildOptions("name");
return (
<div>
...
<select required className={selectClass} >
{o_list}
</select>
...
<button type="button" onClick={(e) => this.add(e, this.props.index)}>
Add
</button>
</div>
);
};
}
I am new to Jest/Enzyme and I am unable to figure out how to mock the external function buildOptions. I am unable to figure out how to mock the external buildOptions function.Could anyone please help me with this.
Here is my test code:
import React from 'react';
import { mount, shallow } from 'enzyme';
import { buildOptions } from '../components/Helper.js';
import DemoComponent from '../components/DemoComponent';
describe('Democomponent', () => {
it('should render required elements', () => {
const wrapper = shallow(
<DemoComponent
index={0}/>
);
//
tests
});
Since you want to mock a named exported function, there is a special trick for that which involves importing all named exports with an * before your tests.
// your test file
import * as Helper from './Helper.js';
const originalBuildOptions = Helper.buildOptions;
Helper.buildOptions = jest.fn();
beforeEach(() => {
jest.clearAllMocks();
// Reset to original implementation before each test
Helper.buildOptions.mockImplementation(originalBuildOptions);
});
test('my test', () => {
// Mock for this test only (will be restored by next `beforeEach` call)
Helper.buildOptions.mockImplementation(() => 'your mock');
});
You can also mock default and named exports directly on import. The official jest documentation uses this method as of 2023. Updating to your use case:
// Your test file
import { buildOptions } from './Helper.js';
jest.mock('./Helper.js', () => {
const originalModule = jest.requireActual('./Helper.js');
// Mock any module exports here
return {
__esModule: true,
...originalModule,
// default: jest.fn(() => 'mocked default export example'),
// Named export mocks
buildOptions: jest.fn(),
};
});
This also works for installed packages as well. For example, I often override specific react-router hooks like useSubmit using the same style of import.
See the official documentation on partial jest named mocks here: https://jestjs.io/docs/mock-functions#mocking-partials
Related
I am writing unit tests for VueJS components and have consulted the "Applying Global Plugins and Mixins" section of Vue Test Utils Common Tips. I have a component that depends on the Vuex store so it makes sense that I would transpose the example under that section for my purposes.
Here is my code for that component's specific .spec.js file:
import { createLocalVue, mount } from '#vue/test-utils'
import AppFooter from '#/components/AppFooter/AppFooter'
import store from '#/store'
describe('AppFooter component', () => {
const localVue = createLocalVue()
localVue.use(store)
it('AppFooter should have header slot', () => {
const AppFooterComponent = mount(AppFooter, {
localVue
})
/* TODO: Replace with a more appropriate assertion */
expect(true).toEqual(true)
})
})
This is pretty faithful to the example provided in the link above. However, the error I receive when I run the test suite is as follows:
Should I be installing the Vue store differently?
To elaborate on my comment, I believe it should look like the following, where you pass in the store on the mount() call.
import { createLocalVue, mount } from '#vue/test-utils'
import AppFooter from '#/components/AppFooter/AppFooter'
import Vuex from 'vuex'
import store from '#/store' //you could also mock this out.
describe('AppFooter component', () => {
const localVue = createLocalVue()
localVue.use(Vuex)
it('AppFooter should have header slot', () => {
const AppFooterComponent = mount(AppFooter, {
store,
localVue
})
/* TODO: Replace with a more appropriate assertion */
expect(true).toEqual(true)
})
})
I believe that you have something like this.$store.getters[someBeautifulGetterName] in you component. To make your tests mount the component your need to initialise store and pass it into your testing component. Just keep in mind that this would be a brand new instance of Vuex. Here is the code
import { shallowMount } from '#vue/test-utils'
import Vue from 'vue'
import Vuex from 'vuex'
import Tags from '#/components/Tags'
Vue.use(Vuex)
Vue.prototype.$store = new Vuex.Store()
const factory = (propsData) => {
return shallowMount(Tags, {
propsData: {
...propsData
}
})
}
describe('Tags', () => {
it("render tags with passed data", () => {
const wrapper = factory({ loading: true })
// TODO:
})
})
I'm new to unit testing with jest & enzyme.
I want to test if the component has a class name 'comment-box' or not.
In the component I conduct a unit test, I do have a div with class name 'comment-box'.
But, when I run a test, it fails.
Probably, Im making an easy mistake since Im new to jest & enzyme.
Could anyone please help me to find out the problem?
Thanks!
Log in my test runner.
FAIL src/__tests__/components/CommentBox.test.js
● CommentBox › has the right class
expect(received).toBe(expected)
Expected value to be (using ===):
true
Received:
false
CommentBox.js
import React, { Component } from 'react';
class CommentBox extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div class="comment-box">
<textarea></textarea>
<button>Submit</button>
</div>
)
}
}
export default CommentBox;
CommentBox.test.js
import React, { Component } from 'react';
import { shallow, mount, render } from 'enzyme';
import CommentBox from '../../components/CommentBox';
jest.unmock('../../components/CommentBox');
describe('CommentBox', () => {
it('has the correct class', () => {
const component = shallow(<CommentBox />);
expect(component.find('div').hasClass('comment-box')).toBe(true);
// I tried this one as well.
// expect(component.find('div').first().hasClass('comment-box')).toBe(true);
});
});
It should be
<div className="comment-box">
Jest provides a way to mock functions as described in their docs
apiGetMethod = jest.fn().mockImplementation(
new Promise((resolve, reject) => {
const userID = parseInt(url.substr('/users/'.length), 10);
process.nextTick(
() => users[userID] ? resolve(users[userID]) : reject({
error: 'User with ' + userID + ' not found.',
});
);
});
);
However these mocks only seem to work when the function is called directly in a test.
describe('example test', () => {
it('uses the mocked function', () => {
apiGetMethod().then(...);
});
});
If I have a React Component defined as such how can I mock it?
import { apiGetMethod } from './api';
class Foo extends React.Component {
state = {
data: []
}
makeRequest = () => {
apiGetMethod().then(result => {
this.setState({data: result});
});
};
componentDidMount() {
this.makeRequest();
}
render() {
return (
<ul>
{ this.state.data.map((data) => <li>{data}</li>) }
</ul>
)
}
}
I have no idea how to make it so Foo component calls my mocked apiGetMethod() implementation so that I can test that it renders properly with data.
(this is a simplified, contrived example for the sake of understanding how to mock functions called inside react components)
edit: api.js file for clarity
// api.js
import 'whatwg-fetch';
export function apiGetMethod() {
return fetch(url, {...});
}
You have to mock the ./api module like this and import it so you can set the implemenation of the mock
import { apiGetMethod } from './api'
jest.mock('./api', () => ({ apiGetMethod: jest.fn() }))
in your test can set how the mock should work using mockImplementation:
apiGetMethod.mockImplementation(() => Promise.resolve('test1234'))
In case the jest.mock method from #Andreas's answer did not work for you. you could try the following in your test file.
const api = require('./api');
api.apiGetMethod = jest.fn(/* Add custom implementation here.*/);
This should execute your mocked version of the apiGetMethod inside you Foo component.
Here is an updated solution for anyone struggling with this in '21. This solution uses Typescript, so be aware of that. For regular JS just take out the type calls wherever you see them.
You import the function inside your test at the top
import functionToMock from '../api'
Then you indeed mock the call to the folder outside of the tests, to indicate that anything being called from this folder should and will be mocked
[imports are up here]
jest.mock('../api');
[tests are down here]
Next we mock the actual function we're importing. Personally I did this inside the test, but I assume it works just as well outside the test or inside a beforeEach
(functionToMock as jest.Mock).mockResolvedValue(data_that_is_returned);
Now here's the kicker and where everyone seems to get stuck. So far this is correct, but we are missing one important bit when mocking functions inside a component: act. You can read more on it here but essentially we want to wrap our render inside this act. React testing library has it's own version of act. It is also asynchronous, so you have to make sure your test is async and also define the destructured variables from render outside of it.
In the end your test file should look something like this:
import { render, act } from '#testing-library/react';
import UserGrid from '../components/Users/UserGrid';
import { data2 } from '../__fixtures__/data';
import functionToMock from '../api';
jest.mock('../api');
describe("Test Suite", () => {
it('Renders', async () => {
(functionToMock as jest.Mock).mockResolvedValue(data2);
let getAllByTestId: any;
let getByTestId: any;
await act(async () => {
({ getByTestId, getAllByTestId } = render(<UserGrid />));
});
const container = getByTestId('grid-container');
const userBoxes = getAllByTestId('user-box');
});
});
Another solution to mock this would be:
window['getData'] = jest.fn();
I am trying to unit test my reactjs component:
import React from 'react';
import Modal from 'react-modal';
import store from '../../../store'
import lodash from 'lodash'
export class AddToOrder extends React.Component {
constructor(props) {
super(props);
this.state = {checked: false}
//debugger
}
checkBoxChecked() {
return true
}
render() {
console.log('testing=this.props.id',this.props.id )
return (
<div className="order">
<label>
<input
id={this.props.parent}
checked={this.checkBoxChecked()}
onChange={this.addToOrder.bind(this, this.props)}
type="checkbox"/>
Add to order
</label>
</div>
)
}
}
export default AddToOrder;
Just to get started I am already struggling to assert the checkBoxChecked method:
import React from 'react-native';
import {shallow} from 'enzyme';
import {AddToOrder} from '../app/components/buttons/addtoorder/addtoorder';
import {expect} from 'chai';
import {mount} from 'enzyme';
import jsdom from 'jsdom';
const doc = jsdom.jsdom('<!doctype html><html><body></body></html>')
global.document = doc
global.window = doc.defaultView
let props;
beforeEach(() => {
props = {
cart: {
items: [{
id: 100,
price: 2000,
name:'Docs'
}]
}
};
});
describe('AddToOrder component', () => {
it('should be handling checkboxChecked', () => {
const wrapper = shallow(<AddToOrder {...props.cart} />);
expect(wrapper.checkBoxChecked()).equals(true); //error appears here
});
});
```
How can I unit test a method on the component? This is the error I am getting:
TypeError: Cannot read property 'checked' of undefined
You are almost there. Just change your expect to this:
expect(wrapper.instance().checkBoxChecked()).equals(true);
You can go through this link to know more about testing component methods using enzyme
For those who find the accepted answer as not working, try using .dive() on your shallow wrapper before using .instance():
expect(wrapper.dive().instance().somePrivateMethod()).toEqual(true);
Reference: Testing component methods with enzyme
Extend of previous answer.
If you have connected component (Redux) , try next code :
const store=configureStore();
const context = { store };
const wrapper = shallow(
<MyComponent,
{ context },
);
const inst = wrapper.dive().instance();
inst.myCustomMethod('hello');
I have the following components:
// Hello.js
export default (React) => ({name}) => {
return (
<div>
Hello {name ? name : 'Stranger'}!
</div>
)
}
// App.js
import createHello from './Hello'
export default (React) => () => {
const Hello = createHello(React)
const helloProps = {
name: 'Jane'
}
return (
<Hello { ...helloProps } />
)
}
// index.js
import React from 'react'
import { render } from 'react-dom'
import createApp from './App'
const App = createApp(React)
render(
<App />,
document.getElementById('app')
)
And I want to set up a test to see if the App component contains one Hello component. I tried the following, using Tape and Enzyme:
import createApp from './App'
import React from 'react'
import test from 'tape'
import { shallow } from 'enzyme'
test('App component test', (assert) => {
const App = createApp(React)
const wrapper = shallow(<App />)
assert.equal(wrapper.find('Hello').length === 1, true)
})
But the result was that the length property of the find result was equal to 0, when I was expecting it to be equal to 1. So, how do I find my Hello component?
There are a couple of things you can do in this case. Enzyme can match component constructors based on the constructor's static .displayName or .name properties, or by referential equality. As a result, the following approaches should all work:
Direct Reference
you can import the actual components in your tests and find them using direct references to the component:
// NavBar-test.js
import NavBar from './path/to/NavBar';
...
wrapper.find(NavBar).length)
Named Function Expressions
If you use named function expressions to create your stateless functional components, the names should still work.
// NavBar.js
module.exports = function NavBar(props) { ... }
Static .displayName property
You can add a static .displayName property on the components:
// NavBar.js
const NavBar = (props) => { ... };
NavBar.displayName = 'NavBar';
Try to import the Hello component in the top of your file and then update your assertion to find the actual component and not the name of it. Like below:
import createApp from './App'
import Hello from './Hello'
import React from 'react'
import test from 'tape'
import { shallow } from 'enzyme'
test('App component test', (assert) => {
const App = createApp(React)
const wrapper = shallow(<App />)
assert.equal(wrapper.find(Hello).length === 1, true)
})
Btw for all the enzyme users out there the assertion would be something like:
expect(wrapper.find(Hello)).toHaveLength(1);