How come this test fails? - unit-testing

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">

Related

Run unit test with Jest, Vue, Vuetify, and Pug

I am currently working on a project that is using Vue, Class based components, typescript, pug, vuetify and Jest for unit testing. I have been trying to run unit tests using jest and have not been able to get them to work. At this point I am pretty lost as to what could be wrong. It seems that there are issues with unit tests when using vueifty which I think I have sorted out but am not certain. When I run the test the test fails because the wrapper is always empty.
Component
<template lang="pug">
v-row(align="center" justify="center")
v-col(cols="6")
v-card
v-form(ref="loginForm" v-model="valid" v-on:keyup.enter.native="login")
v-card-title#title Login
v-card-text
v-text-field(class="mt-4" label="Username" required outlined v-model="username" :rules="[() => !!username || 'Username Required.']")
v-text-field(label="Password" required outlined password :type="show ? 'text' : 'password'" :append-icon="show ? 'visibility' : 'visibility_off'" #click:append="show = !show" v-model="password" :rules="[() => !!password || 'Password Required.']")
v-alert(v-if="error" v-model="error" type="error" dense dismissible class="mx-4")
| Error while logging in: {{ errorMsg }}
v-card-actions()
div(class="flex-grow-1")
v-btn(class="mr-4" color="teal" :disabled="!valid" large depressed #click="login") Login
div Forgot password?
a(href="/forgot-password" class="mx-2") Click here
div(class="my-2") Don't have an account?
a(href="/signup" class="mx-2") Signup
| for one
</template>
<script lang="ts">
import { AxiosError, AxiosResponse } from 'axios';
import JwtDecode from 'jwt-decode';
import { Component, Vue } from 'vue-property-decorator';
import { TokenDto, VForm } from '#/interfaces/GlobalTypes';
#Component({
name: 'LoginForm',
})
export default class Login extends Vue {
private password: string = '';
private username: string = '';
private show: boolean = false;
private error: boolean = false;
private errorMsg: string = '';
private valid: boolean = false;
... removed rest for brevity
Test
import LoginForm from '#/components/auth/LoginForm.vue';
import login from '#/views/auth/LoginView.vue';
import { createLocalVue, mount } from '#vue/test-utils';
import Vue from 'vue';
import Vuetify from 'vuetify';
// jest.mock('axios')
Vue.use(Vuetify)
const localVue = createLocalVue();
console.log(localVue)
describe('LoginForm.vue', () => {
let vuetify: any
beforeEach(() => {
vuetify = new Vuetify()
});
it('should log in successfully', () => {
const wrapper = mount(LoginForm, {
localVue,
vuetify
})
console.log(wrapper.find('.v-btn'))
});
});
The LoginForm is loaded properly but it does not seeem that that mount creates the wrapper for some reason. When I log the wrapper I get:
VueWrapper {
isFunctionalComponent: undefined,
_emitted: [Object: null prototype] {},
_emittedByOrder: []
}
Any ideas are greatly appericated
you can try:
wrapper.findComponent({name: 'v-btn'})
I guess I am late but I made it work.
I noticed you tried to find VBtn component by 'v-btn' class but VBtn doesn't have it by default. That's why I decided to stub it with my own VBtn that has 'v-btn' class.
import { shallowMount, Wrapper } from '#vue/test-utils'
import Login from '#/components/Login/Login.vue'
import Vue from 'vue'
import Vuetify from 'vuetify'
Vue.use(Vuetify)
let wrapper: Wrapper<Login & { [ key: string]: any }>
const VButtonStub = {
template: '<button class="v-btn"/>'
}
describe('LoginForm.vue', () => {
beforeEach(() => {
wrapper = shallowMount(Login, {
stubs: {
VBtn: VButtonStub
}
})
})
it('should log in successfully', () => {
console.log(wrapper.html())
})
})
After test passed you will see in console log that stubbed component has 'v-btn' class. You can add yours and work with it like you want.

Mock named exports for testing using Jest

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

Why do I get method is not a function in my jesttest?

My jest unittest looks like this:
import React from 'react';
import renderer from 'react-test-renderer';
import ReactTestUtils from 'react-dom/test-utils'
import Calculator from "./calculator";
test('test that calculator', () => {
const component = renderer.create(
<Calculator></Calculator>
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();
console.log('component=',component.refs);
// Simulate click on button -> trigger sumCalc()
ReactTestUtils.Simulate.click(component.refs.button);
});
When I run the test I get:
TypeError: Cannot read property 'button' of undefined
My react component looks like this:
import React, {Component} from 'react';
export default class Calculator extends Component {
constructor(props) {
super(props);
this.calcSum = this.calcSum.bind(this);
this.state = {sum: 0};
}
calcSum() {
console.log('this.refs.one=', this.refs.one);
let s = Number(this.refs.one.value) + Number(this.refs.two.value);
this.setState({sum: s});
}
render() {
return (<div>
<input type="text" placeholder="number 1" ref="one"/>
<input type="text" placeholder="number 2" ref="two"/>
<button ref="button" onClick={this.calcSum}>sum</button>
sum: {this.state.sum}
</div>
);
}
}
How can I avoid this error? what am I missing?
The component works when rendered into the DOM but the unit test has issues.
component.toJSON() returns a JSON not a JavaScript object. Moreover calcSum is not a prop, instead it is a method defined on your component class.
Hence you could use getInstance() method to manually invoke calcSum.
Try this:
const component = renderer.create(<Calculator />);
component.getInstance().calcSum();
Now you can see that console.log output from calcSum.

How to unit test a method of react component?

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');

Expected false to be true when test react component with jasmine jsdom and enzyme

When I ran the jasmine as a gulp task, the test seems runs well, though first one is always considered failed. I am not sure where the problem is.
React Component
import React, { PropTypes } from 'react';
const propTypes = {};
const defaultProps = {};
class Foo extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="foo"> </div>
);
}
}
Foo.propTypes = propTypes;
Foo.defaultProps = defaultProps;
export default Foo;
Spec File
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import Foo from './foo.react';
import jsDom from 'jsdom';
global.document = jsDom.jsdom('');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
if (typeof global[property] === 'undefined') {
global[property] = document.defaultView[property];
}
});
global.navigator = {
userAgent: 'node.js'
};
describe("A suite", function() {
it("contains spec with an expectation", function() {
console.log(shallow(<Foo />));
expect(shallow(<Foo />).contains(<div className="foo" />)).toBe(true);//.toBe(true)
});
it("contains spec with an expectation", function() {
expect(shallow(<Foo />).is('.foo')).toBe(true);
});
it("contains spec with an expectation", function() {
expect(mount(<Foo />).find('.foo').length).toBe(1);
});
});
Result
Found out I have to change my return to
<div className="foo" /> instead of <div className="foo"> </div>
Then the test will pass.
Do not yet understand why they are different still though.
I think the issue may be in the white space you have in <div className="foo"> </div>
contains checks for an exact match, and an empty tag is different than the same tag containing a space characters. See also this discussion for a possible workaround involving elem.html()