unit-testing component whose props gets value from react navigation component - unit-testing

How can I write a unit test for a React Native component which gets its state's value from React Navigation, more specific this.props.navigation.state.params? This is the component class:
class RecAreas extends Component{
static navigationOptions =({navigation}) => ({
title: navigation.state.params.title,
headerStyle: {
backgroundColor: "#000000",
},
headerTintColor: '#facf33',
});
constructor(props){
super(props);
const params = this.props.navigation.state.params;
this.state={
key:params.gymId,
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
}),
};
this.mainRef = db.ref("facilities");
}
componentDidMount(){
this.listenForItem(this.mainRef)
}
I Could not figure out how to pass the nested function as props for the unit test. In this case this.props.navigation, this.props.navigation.state, this.props.navigation.state.params are all objects. How do I mock them for unit test? In the below example I get TypeError: Cannot read property 'gymId' of undefined which makes sense because params is not defined. I need help to resolve this. This is a unit test for the component. Thank you in advance!
(PS: it would be great to know as well how to mock dataSource props as well. One way I thought I could do this is to make a fake dataSource data structure (print out the dataSource and look at its structure). Any pointers would be helpful. Thanks!)
import React from "react";
import RecAreas from "../../app/screens/RecAreas";
import renderer from "react-test-renderer";
describe ("<RecAreas", () => {
it("renders without crashing", () => {
const navigationMock = {state: jest.fn()};
const rendered = renderer.create(<RecAreas navigation=
{navigationMock}/>).toJSON();
expect(rendered).toBeTruthy();
expect(rendered).toMatchSnapshot();
});
}

hey you have mock the props also to generate the tree for snapshot
like this
import React from "react";
import RecAreas from "../../app/screens/RecAreas";
import renderer from "react-test-renderer";
describe ("<Test", () => {
it("renders without crashing", () => {
const navigationMock = { state: { params: { gymId: "1234" } } };
const rendered = renderer
.create(<RecAreas navigation={navigationMock} />)
.toJSON();
expect(rendered).toBeTruthy();
expect(rendered).toMatchSnapshot();
});
})
or you try Enzyme allows for direct manipulation of the props and state of the components

Related

Unit test vue.js component with inline-template

I am using Vue 2 to enhance a Ruby on Rails engine, using inline-template attributes in the existing Haml views as templates for my Vue components.
Is it possible to test the methods of a component defined like this? All the testing examples I can find assume the use of single-file .vue components.
These tests (using Mocha and Chai) fail with [Vue warn]: Failed to mount component: template or render function not defined.
Example Component:
//main-nav.js
import Vue from 'vue'
const MainNav = {
data: function() {
return {open: true}
},
methods: {
toggleOpen: function(item) {
item.open = !item.open
}
}
}
export default MainNav
Example Test:
//main-nav.test.js
import MainNav from '../../admin/main-nav'
describe('MainNav', () => {
let Constructor
let vm
beforeEach(() => {
Constructor = Vue.extend(MainNav)
vm = new Constructor().$mount()
})
afterEach(() => {
vm.$destroy()
})
describe('toggleOpen', () => {
it('has a toggleOpen function', () => {
expect(vm.MainNav.toggleOpen).to.be.a('function')
})
it('toggles open from true to false', () => {
const result = MainNav.toggleOpen({'open': true})
expect(result).to.include({open: false})
})
})
})
It turns out you can still specify a template in the component file, and any inline-template templates will be used in favour of that.

How to test react component correctly?

Recently I am learning to test React with jest and enzyme, It seems hard to understand what a unit test is it, my code
import React from "react";
class App extends React.Component {
constructor() {
super();
this.state = {
value: ""
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
const value = e.target.value;
this.setState({
value
});
}
render() {
return <Nest value={this.state.value} handleChange={this.handleChange} />;
}
}
export const Nest = props => {
return <input value={props.value} onChange={props.handleChange} />;
};
export default App;
and my test
import React from "react";
import App, { Nest } from "./nest";
import { shallow, mount } from "enzyme";
it("should be goood", () => {
const handleChange = jest.fn();
const wrapper = mount(<App />);
wrapper.find("input").simulate("change", { target: { value: "test" } });
expect(handleChange).toHaveBeenCalledTimes(1);
});
IMO, the mocked handleClick will intercept the handleClick on App,
if this is totally wrong, what's the right way to use mock fn and test the handleClick be called.
Another: I search a lot, read the similar situations, seem like this iscontra-Unit Test,
Probably I should test the two component separately, I can test both components,
test the
<Nest value={value} handleChange={handleChange} />
by pass the props manually, and then handleChangeinvoked by simulate change
it passed test.
but how can I test the connection between the two?
I read
some work is React Team's Work
...
I don't know which parts I have to test in this case, and Which parts react already tested and don't need me to test. That's confusing.
You should take the path of testing the Nest component in isolation first, passing your mocked handleChange as a prop, to verify that input changes are being propagated.
If you want to test the state part, then you can get the instance of your App class from enzyme and call that method directly:
it("should update the Nest value prop when change is received", () => {
const wrapper = mount(<App />);
const instance = wrapper.instance()
instance.handleChange( { target: { value: "test" } })
const nestComponent = wrapper.find("Nest").first()
expect(nestComponent).prop('value').toEqual('test');
});
This a very very basic, almost not needed to test piece of code, but it will get your test coverage up if that's what you're after.
Doc for instance: http://airbnb.io/enzyme/docs/api/ReactWrapper/instance.html
If you want to test for the connection. From what I see, the nest component is a child component inside the App component. You could test that <App /> contains `.
describe('<App />', () => {
it('should contain a nest component', () => {
const wrapper = mount(<App />);
expect(wrapper.find(<Nest />)).toHaveLength(1);
});
});
Secondly, since the onChange event on the nest component updates the state in the App component, you can also test for state changes since its a behavior you expect.
it('should update state', () => {
//find input and simulate change with say {value: 'new value'} and then
expect(wrapper.state().value).toBe('newValue');
});
I hope this helps.

Jest -- Mock a function called inside a React Component

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

How can I test computed properties in VueJS?

I'm using VueJS from Vue CLI. So all my components are in .vue format.
In one of my components, I have an array called fields in the data section.
//Component.vue
data() {
return {
fields : [{"name" : "foo", "title" : "Foosteria"}, {"name" : "bar", "title" : "Barrista"}]
}
}
I have a computed property that is a subset of fields
//Component.vue
computed : {
subsetOfFields () {
// Something else in component data determines this list
}
}
I've set up all of my unit tests in jasmine like this and they work fine.
//Component.spec.js
import Vue from 'vue'
import MyComponent from 'Component.vue'
describe("Component test", function() {
var myComponentVar = new Vue(MyComponent);
var vm = myComponentVar.$mount();
beforeEach(function() {
vm = myComponentVar.$mount();
);
afterEach(function() {
vm = myComponentVar.$destroy();
});
it("First spec tests something", function() {
...
});
});
For everything else, doing something inside the spec, then running assertions on the data objects works just fine. However, running an assertion on subsetOfFields always returns an empty array. Why so? What should I do, in order to be able to test it?
FYI, I even tried nesting the spec inside another describe block and then adding a beforeEach which initializes the fields array. It did not work.
However, initializing fields inside the generic beforeEach function worked. But I don't want to initialize the fields array with that mock data for the other specs.
I came across this link that talks about testing and the section you'll need to look at is the Vue.nextTick(...) section
https://alligator.io/vuejs/unit-testing-karma-mocha/
The block I'm talking about is below:
import Vue from 'vue';
// The path is relative to the project root.
import TestMe2 from 'src/components/TestMe2';
describe('TestMe2.vue', () => {
...
it(`should update when dataText is changed.`, done => {
const Constructor = Vue.extend(TestMe2);
const comp = new Constructor().$mount();
comp.dataProp = 'New Text';
Vue.nextTick(() => {
expect(comp.$el.textContent)
.to.equal('New Text');
// Since we're doing this asynchronously, we need to call done() to tell Mocha that we've finished the test.
done();
});
});
});

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