Unable to write unit test case for button click event - javascript

I am working on the React JS application. Whenever the user presses Enter I am firing some event as below.
dispatchSearch() {
if (!this.isSearchButtonDisabled()) {
const searchTerms = { [this.state.searchType]: this.state.searchTerm };
const searchDbTarget = '';
const options = {};
this.props.searchParameters(searchTerms, searchDbTarget, options, this.state.allOpenStoresSearchTerms.selectedOption);
}
}
The above code works as expected. Below is my unit test case for the above code.
it('should dispatch a keycode when keycode value is set', () => {
component.setState({ searchTerm: 'some-value', allOpenStoresSearchTerms: {selectedOption: {value: 'true', label: 'Open Stores'}} });
component.find('SearchInput').props().onKeyPress({ key: 'Enter' });
expect(dispatchEvent).toBeCalled();
expect(dispatchEvent).toBeCalledWith({ simsKeycode: 'some-value', allOpenStoresSearchTerms: {selectedOption: {value: 'true', label: 'Open Stores'}} });
});
This unit test case fails and throws below error
Expected mock function to have been called with:
{"allOpenStoresSearchTerms": {"selectedOption": {"label": "Open Stores", "value": "true"}}, "simsKeycode": "some-value"} as argument
1, but it was called with {"simsKeycode": "some-value"}.
undefined as argument 2, but it was called with "".
undefined as argument 3, but it was called with {}.
undefined as argument 4, but it was called with {"label": "Open Stores", "value": "true"}.
May I know what I am missing in the above code? Any help would be greatly appreciated. Thanks

setState method works only when you're mount rendering your component. it doesn't work on shallow render.

Related

How to use spread operator in setstate react class component

I am developing a component where I will get the data from a call back function. Initially the state of the component will be empty [], later once the callback function is called I need to update the values into the state. At a time I'll recive only one array, meaning user can add one item at a time that item will consists of nested objects and array values. I have added the logic for the same to handle the scenario, but when I am testing in jest when I am trying to add another set of item from mock meaning the user can select next item when the done with selecting and submitting the first item at that time my logic is getting failed, I am not getting where I went wrong, could any one help me to resolve this issue, thanks in advance! I have added the mock data structure and logic and jest test below.
Mock:
const items = {
itemList: {
itemOne: [{
id: "01",
category: "It-A",
isCreated:"true"
}],
itemDesc:[{
id:"01",
type:"A-1",
isCreated:"true"
}]
}
ItemID:'123'
}
Code:
class ItemComp extends React.Component{
this.state = {
processingItems:[]
onAddItemHandle = (processingItem) => {
this.setState(prevState => ({
processingItems: [...prevState.processingItems, processingItem]
}))
}
JEST:
describe('handleonAddItem', () => {
it('should allow to add multiple items based on prevState', () => {
const compView = mountWithIntl(
<compView
itemId={12}
/>
}
const instance = compView.find(compViewComponent).instance();
instance.onAddItemHandle(items) // when I am giving only one instance my logic is working
instance.onAddItemHandle(items) //when I am giving it for second time it's failing I am getting error like expected - 0 , received +18 I want to update the items here when user clicks for second time but it is failing.
expect(instance.state.processingItems).toEqual([items])
Missing a ',' before the ItemID is the only issue I faced while reproducing.- https://codesandbox.io/s/intelligent-chaplygin-0ot56e?file=/src/App.js
const items = {
itemList: {
itemOne: [{
id: "01",
category: "It-A",
isCreated:"true"
}],
itemDesc:[{
id:"01",
type:"A-1",
isCreated:"true"
}]
},
ItemID:'123'
}

cause of TypeError: Cannot read properties of undefined

I'm trying to fetch some data from an API. The below code "works" when I log the results to console like console.log(liveInfo.tracks), but when I try to do console.log(liveInfo.tracks.current) it fails with this error: TypeError: Cannot read properties of undefined (reading 'current'). Isn't liveInfo.tracks.current how one would normally access the key-value pair?
componentDidMount() {
fetch('https://kchungradio.airtime.pro/api/live-info-v2')
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
liveInfo: result
})
}
)
}
The json looks more or less like this:
{
"station": {
"env": "production",
},
"tracks": {
"previous": {
"name": "a",
"metadata": {
"id": 1,
},
},
"current": {
"name": "b",
"metadata": {
"id": 2,
}
}
}
}
Because at some point liveInfo.tracks was undefined
Although there is a lack of hints, a common mistake when fetching data from lifecycle is trying to retrieve the value through the state before setData occurs.
Before you use liveInfo, make sure that data fetching is finished
like this
class SomeComponent = {
render() {
if(!this.state.liveInfo?.tracks?.current) return null
....
}
}
It looks you are trying to access to the current before it is filled on the componentDidMount, it means before the fetch has been performed. I suggest you to initialize the state like this:
state = {
isLoaded: false,
liveInfo: {
tracks: {
curent: {}
}
}
};
So you will be able to access the current property inside tracks without facing the TypeError. I made a codesandbox, so you can check an example there.
If this does not solve your problem, please let me know ;)
Your call looks right,
another way to get the value is console.log(liveInfo.tracks["current"]);
but I think your tracks has no value at runtime. Maybe you can show us more code where you are call console.log.
Maybe you run twice in your statement and at first time it is undefined and throw the error. So add a null check like this console.log(liveInfo?.tracks?.current);
Use Question mark (?)
? will check for null. If your object is null ? will handle it.
liveInfo?.tracks?.current
this is the right approach.
Further -
liveInfo?.tracks?.current?.metadata

Postman conditional tests if json body array is empty = skip tests

I want to integrate Postman/ Newman API tests into CICD, so the test results should always be passed (or skipped). Therefor I want to use conditional tests, dependent on the data of the response.
I tried the method described on GitHub, but the condition in my case is very different.
So if the json body of the response contains an empty array, tests should be skipped. If not, perform tests...
Empty data
{
"data": []
}
Testable data
{
"data": [
{
"key1": "value1",
"key2": {
"amount": 1357,
"unit": "units"
},
"from": "2019-08-01",
"to": "2019-08-31",
}
]
}
Test script
let response = JSON.parse(responseBody);
pm.test("Status code is 200", function() {
pm.expect(pm.response.code).to.equal(200);
});
(pm.expect(pm.response.json().data).to.be.empty === true ? pm.test.skip : pm.test)('Body is empty', function () {
pm.environment.set("key2Amount", response.data[0].key2.amount);
var key2Amount = pm.environment.get("key2Amount");
pm.test("Response includes corresponding amount", function () {
pm.expect(pm.response.json().data[0].key2.amount).to.eql(key2Amount);
});
});
Empty data: TypeError: Cannot read property 'key2' of undefined.
Testable data: AssertionError: expected [ Array(1) ] to be empty.
I've also tried it with
(pm.expect([]).to.be.an('array').that.is.empty ? pm.test : pm.test.skip)
Testable data: Tests performed positive.
Empty data: TypeError: Cannot read property 'key2' of undefined. Why not skipped?
Further
(pm.expect([]).to.be.empty ? pm.test.skip : pm.test)
Empty data: skipped tests
Testable data: skipped tests
What would be the correct condition on the array to make the tests run or skipped?
Could you use something like this:
let response = pm.response.json();
pm.test("Status code is 200", function() {
pm.expect(pm.response.code).to.equal(200);
});
let skipTest = (response.data === undefined || response.data.length === 0);
(skipTest ? pm.test.skip : pm.test)('Body is empty', function () {
pm.environment.set("key2Amount", response.data[0].key2.amount);
pm.test("Response includes corresponding amount", function () {
pm.expect(response.data[0].key2.amount).to.eql(pm.environment.get("key2Amount"));
});
});

React-native: undefined is not an object

Probably it's a newbie question... I get a json response with an object from a fetch() running into a function on componentDidMount(). The result is saved into a state
data:
{
id: 1,
name: 'joseph',
tickets:
[
{id: 334, descripton: 'example1'},
{id: 768, descripton: 'example2'},
],
}
I need to list this array "tickets" in render ().
componentDidMount(){
this.getFetch(...);
}
showTickets(WTickets){
console.log(WTickets);
WTickets.map((item)=>{
return (item.id)
})
}
render(){
return(
<View>
{this.showTickets(this.state.data.tickets)}
</View>
)
}
But the "first return" is "undefined", generating error and then the state changes to the correct result. The fetch is running with async await, but still show the "undefined" first.
The console.log show 2 results: one "undefined" and another with the result.
Any good soul to help me, please?
It's because at the start this.state.data.tickets is undefined and you are calling it in the render function which is not gonna wait until this.getFetch() finishes. So.. you can do a conditional rendering to check if this.state.data.tickets exist in rendering
replace {this.showTickets(this.state.data.tickets)}
with {this.state.data!==undefined? this.showTickets(this.state.data.tickets) : null}
What we are doing here is first checking if this.state.data.tickets is not undefined. While it is undefined (at the start) we return null, when it stops being undefined we call this.showTickets.
You can even initialize this.state.data as an empty array, and you can delete the part when we check if it's undefined since an empty array will return false
constructor() {
super();
this.state = {
data: []
};
}
....
....
//in render function
{this.state.data? this.showTickets(this.state.data.tickets) : null}
...

React Select Async options not showing

I have an API call which is returning data and the best I can see I am returning the options in the correct way but for some reason I can't get React Select to show the options. Is there something that I am missing?
searchGroups(searchString){
if(!searchString) return Promise.resolve({ options: [] });
UserGroups.getUserGroups(searchString).then((res) => {
let groups = [];
groups = res.groups.map((d) => ({
value: d.group_ID,
label: d.group_name
}))
return {options: groups};
}, (e) => {
this.setState({
searchError: e.message
})
})
}
From what I can see the groups array is (upon a search) returning as
[
{value: 1, label: "Admins"}
{value: 22, label: "Asset Group"}
{value: 2, label: "Read-only"}
]
However the search box is being suspended with a "loading..." message and the load spinner stays. I can see the API has returned but no options are being displayed.
This is how I implement the Select is there an option I am missing? I have tried both valueKey and labelKey but neither have worked for me either.
<Select.Async
multi={true}
onChange={this.onChange}
loadOptions={this.searchGroups}
value={this.state.value}
/>
I'm sure it is how I'm returning the data but not sure where this is going wrong and what formatting I need to correct. Any help would be greatly appreciated.
The problem was a missing return before UserGroups.getUserGroups(... This caused the async code to get executed and show up in the network log, but the results wouldn't reach Select.Async. It would be nice if react-select would give an error if calling loadOptions returns undefined, but in that case it assumes a callback will be used to provide the result.

Categories