Jest testing, keeps return undefined? - javascript

I'm trying to test a function with jest, and I simply can figure out what's wrong? It keeps saying it expects to return the output, but got undefined. I have tested the function elsewhere where it seems to return the correct array.
I'm calling my my function and passing it an Object, it's then supposed to return an array. Then I'm calling .toEqual(output) which is an array.
//This is my function
const allAddresses = [
];
const updateAllAddresses = (obj) => {
const transferAmount = obj.transferAmount;
const to = obj.to;
const transferAddress = obj.address;
const newBalance = obj.newBalance;
const addressArr = [...allAddresses];
console.log("This addressArr", addressArr);
console.log("this is obj", obj);
//To set your account to the new balance after transfer and
//to check if the address you transfer to is your own account
addressArr.map((address) => {
if (address.account === transferAddress) {
console.log("This is inside the map !!!!");
address.balance = Number(newBalance);
}
if (address.account === to) {
console.log("2");
address.balance = Number(transferAmount) + Number(address.balance);
}
console.log("last part of the testing", addressArr);
return addressArr;
});
};
const obj = {
};
const output = [
];
//This is my test
describe("Update array", () => {
test("update the array with the new information", () => {
expect(updateAllAddresses(obj)).toEqual(output);
});
});

You cannot short circuit and return inside a map function. You should return the object after the map
Also, when you change address inside the map; It really does not change anything, since that address variable will be removed from memory on next iteration

There is a problem with your updateAllAddresses method.
You are not returning anything then the result of your function becomes undefined;
add return to where you are using .map method.
return addressArr.map((address) => {
if (address.account === transferAddress) {
console.log("This is inside the map !!!!");
address.balance = Number(newBalance);
}
if (address.account === to) {
console.log("2");
address.balance = Number(transferAmount) + Number(address.balance);
}
console.log("last part of the testing", addressArr);
return address;
});

Related

map is not a function in testcafe

I am not able to use a map function inside a client function.
export function availableAudioBitrates() {
const getOptionNames = ClientFunction(() => {
const select = document.querySelector('[data-testid=audioBitrate-setting]');
const options = select.querySelectorAll('option');
console.log(typeof options);
//const values = [];
const values = options.map((option) => option.TextContent);
//options.forEach((option) => values.push(option.textContent));
return values;
});
return getOptionNames();
}
I have "options.foreach" statement working, but with map function, it is throwing an error that options.map is not a function.
Check the value of options, its either undefined or not an array. .map() requires an array to run, anything else will cause that error
Because that is a HTMLCollection, not an array.
Use Array.form(select.querrySelectorAll('option')).
export function availableAudioBitrates() {
const getOptionNames = ClientFunction(() => {
const select = document.querySelector('[data-testid=audioBitrate-setting]');
const options = Array.from(select.querySelectorAll('option'));
console.log(typeof options);
//const values = [];
const values = options.map((option) => option.TextContent);
//options.forEach((option) => values.push(option.textContent));
return values;
});
return getOptionNames();
}

Wait for all Firebase data query requests before executing code

I am trying to fetch data from different collections in my cloud Firestore database in advance before I process them and apply them to batch, I created two async functions, one to capture the data and another to execute certain code only after all data is collected, I didn't want the code executing and creating errors before the data is fetched when i try to access the matchesObject after the async function to collect data is finished, it keeps saying "it cannot access a property matchStatus of undefined", i thought took care of that with async and await? could anyone shed some light as to why it is undefined one moment
axios.request(options).then(function(response) {
console.log('Total matches count :' + response.data.matches.length);
const data = response.data;
var matchesSnapshot;
var marketsSnapshot;
var tradesSnapshot;
var betsSnapshot;
matchesObject = {};
marketsObject = {};
tradesObject = {};
betsObject = {};
start();
async function checkDatabase() {
matchesSnapshot = await db.collection('matches').get();
matchesSnapshot.forEach(doc => {
matchesObject[doc.id] = doc.data();
console.log('matches object: ' + doc.id.toString())
});
marketsSnapshot = await db.collection('markets').get();
marketsSnapshot.forEach(doc2 => {
marketsObject[doc2.id] = doc2.data();
console.log('markets object: ' + doc2.id.toString())
});
tradesSnapshot = await db.collection('trades').get();
tradesSnapshot.forEach(doc3 => {
tradesObject[doc3.id] = doc3.data();
console.log('trades object: ' + doc3.id.toString())
});
betsSnapshot = await db.collection('bets').get();
betsSnapshot.forEach(doc4 => {
betsObject[doc4.id] = doc4.data();
console.log('bets object: ' + doc4.id.toString())
});
}
async function start() {
await checkDatabase();
// this is the part which is undefined, it keeps saying it cant access property matchStatus of undefined
console.log('here is matches object ' + matchesObject['302283']['matchStatus']);
if (Object.keys(matchesObject).length != 0) {
for (let bets of Object.keys(betsObject)) {
if (matchesObject[betsObject[bets]['tradeMatchId']]['matchStatus'] == 'IN_PLAY' && betsObject[bets]['matched'] == false) {
var sfRef = db.collection('users').doc(betsObject[bets]['user']);
batch11.set(sfRef, {
accountBalance: admin.firestore.FieldValue + parseFloat(betsObject[bets]['stake']),
}, {
merge: true
});
var sfRef = db.collection('bets').doc(bets);
batch12.set(sfRef, {
tradeCancelled: true,
}, {
merge: true
});
}
}
}
});
There are too many smaller issues in the current code to try to debug them one-by-one, so this refactor introduces various tests against your data. It currently won't make any changes to your database and is meant to be a replacement for your start() function.
One of the main differences against your current code is that it doesn't unnecessarily download 4 collections worth of documents (two of them aren't even used in the code you've included).
Steps
First, it will get all the bet documents that have matched == false. From these documents, it will check if they have any syntax errors and report them to the console. For each valid bet document, the ID of it's linked match document will be grabbed so we can then fetch all the match documents we actually need. Then we queue up the changes to the user's balance and the bet's document. Finally we report about any changes to be done and commit them (once you uncomment the line).
Code
Note: fetchDocumentById() is defined in this gist. Its a helper function to allow someCollectionRef.where(FieldPath.documentId(), 'in', arrayOfIds) to take more than 10 IDs at once.
async function applyBalanceChanges() {
const betsCollectionRef = db.collection('bets');
const matchesCollectionRef = db.collection('matches');
const usersCollectionRef = db.collection('users');
const betDataMap = {}; // Record<string, BetData>
await betsCollectionRef
.where('matched', '==', false)
.get()
.then((betsSnapshot) => {
betsSnapshot.forEach(betDoc => {
betDataMap[betDoc.id] = betDoc.data();
});
});
const matchDataMap = {}; // Record<string, MatchData | undefined>
// betIdList contains all IDs that will be processed
const betIdList = Object.keys(betDataMap).filter(betId => {
const betData = betDataMap[betId];
if (!betData) {
console.log(`WARN: Skipped Bet #${betId} because it was falsy (actual value: ${betData})`);
return false;
}
const matchId = betData.tradeMatchId;
if (!matchId) {
console.log(`WARN: Skipped Bet #${betId} because it had a falsy match ID (actual value: ${matchId})`);
return false;
}
if (!betData.user) {
console.log(`WARN: Skipped Bet #${betId} because it had a falsy user ID (actual value: ${userId})`);
return false;
}
const stakeAsNumber = Number(betData.stake); // not using parseFloat as it's too lax
if (isNaN(stakeAsNumber)) {
console.log(`WARN: Skipped Bet #${betId} because it had an invalid stake value (original NaN value: ${betData.stake})`);
return false;
}
matchDataMap[matchId] = undefined; // using undefined because its the result of `doc.data()` when the document doesn't exist
return true;
});
await fetchDocumentsById(
matchesCollectionRef,
Object.keys(matchIdMap),
(matchDoc) => matchDataMap[matchDoc.id] = matchDoc.data()
);
const batch = db.batch();
const queuedUpdates = 0;
betIdList.forEach(betId => {
const betData = betDataMap[betId];
const matchData = matchDataMap[betData.tradeMatchId];
if (matchData === undefined) {
console.log(`WARN: Skipped /bets/${betId}, because it's linked match doesn't exist!`);
continue;
}
if (matchData.matchStatus !== 'IN_PLAY') {
console.log(`INFO: Skipped /bets/${betId}, because it's linked match status is not "IN_PLAY" (actual value: ${matchData.matchStatus})`);
continue;
}
const betRef = betsCollectionRef.doc(betId);
const betUserRef = usersCollectionRef.doc(betData.user);
batch.update(betUserRef, { accountBalance: admin.firestore.FieldValue.increment(Number(betData.stake)) });
batch.update(betRef, { tradeCancelled: true });
queuedUpdates += 2; // for logging
});
console.log(`INFO: Batch currently has ${queuedUpdates} queued`);
// only uncomment when you are ready to make changes
// batch.commit();
}
Usage:
axios.request(options)
.then(function(response) {
const data = response.data;
console.log('INFO: Total matches count from API:' + data.matches.length);
return applyBalanceChanges();
}

How to access a local variable's value in this situation?

I'm trying to read the number of times an event has been logged and increment/decrement a variable accordingly. Since I can't use this.setState inside the getPastEvent (because it generates an Unhandled Runtime Error which is TypeError: Cannot read property 'setState' of undefined), I'm opting for this method where I perform my counting on a local variable then save it to the state variable.
The issue here is when I use this.setState({totalBidders: biddersnumber}); at the end of the function, I receive the value zero where in my case it should be two! How can I get the value of the counter biddersnumber in this situation?
componentDidMount = async () => {
const accounts = await web3.eth.getAccounts();
const plasticBaleSC = plasticBaleContract(this.props.address);
var biddersnumber = 0;
var highestbid = 0;
plasticBaleSC.getPastEvents('allEvents', { fromBlock: 0, toBlock: 'latest' }, function (error, events) {
console.log(events);
events.forEach(myfunction);
function myfunction(item, index) {
if (item.event === 'bidderRegistered') {
console.log(item);
biddersnumber++;
//value is two here
console.log(biddersnumber);
} else if (item.event === 'bidPlaced') {
} else if (item.event === 'bidderRegistered') {
} else if (item.event === 'bidderExited') {
console.log(item);
biddersnumber--;
} else if (item.event === 'auctionStarted') {
}
}
});
//Value is zero here
this.setState({ totalBidders: biddersnumber });
}
Using comments on this question, I did the following updates to resolve the issue. Thank you Andrea!
componentDidMount = async () => {
const accounts = await web3.eth.getAccounts();
const plasticBaleSC = plasticBaleContract(this.props.address);
var biddersnumber = 0;
var highestbid =0;
plasticBaleSC.getPastEvents("allEvents",{fromBlock: 0, toBlock:'latest'},(error, events)=>{
console.log(events);
const myfunction = (item,index) => {
if(item.event==='bidderRegistered'){
console.log(item);
biddersnumber++;
console.log(biddersnumber);
}else if(item.event==='bidPlaced'){
}else if(item.event==='bidderRegistered'){
}else if (item.event==='bidderExited'){
console.log(item);
biddersnumber--;
}else if(item.event==='auctionStarted'){
//console.log(item);
//this.setState({highestBid: item.returnValues['startingAmount']});
}
};
events.forEach(myfunction);
this.setState({totalBidders: biddersnumber});
});
};
You need to put the call to setState inside your callback:
// ....
var highestbid =0;
const that = this
// ....
// Value is two here
that.setState({totalBidders: biddersnumber});
});
//Value is zero here
};
You'll need to deal with this, so assign it to that like it's 2010.

Return array value from produce function | immer.js

I am using immer.js to perform operations on arrays in the state.
Arrays: basicRecipe and recipeBasicRecipe.
I am modifying the draft.basicRecipe in the produce function. My objective is to return the updated "draft.basicRecipe" value and store the same in temparray1.
let temparray1 = produce(state, draft => {
draft.basicRecipe = draft.basicRecipe.map(item => {
let element = draft.recipeBasicRecipes.find(e => e._id === item._id);
console.log(element);
if (element) {
item.details = item.details.map(e => {
let detail = element.details.find(d => d._id === e._id);
if (detail) {
e.rate = detail.rate;
}
return e;
});
}
return item;
});
return draft.basicRecipe;
});
console.log(temparray1);
When I return the draft I am able to see updated basicRecipe nested in output.
I am getting the below error when I try to return the array i.e draft.basicRecipe
[Immer] An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft
This code is a mess. You are using map which returns a new array but you're also trying to mutate the original draft object.
This is still unreadable and confusing, but at least by using forEach instead of map we are just mutating and not trying to do two things at once.
let temparray1 = produce(state, (draft) => {
draft.basicRecipe.forEach((item) => {
let element = draft.recipeBasicRecipes.find((e) => e._id === item._id);
if (element) {
item.details.forEach((e) => {
let detail = element.details.find((d) => d._id === e._id);
if (detail) {
e.rate = detail.rate;
}
});
}
});
});

Cannot use object key to reference method in Javascript

I have a set of methods for validating input stored in a variable val such that I can call them like val.email or val["email"]. I'm trying to create a general function that will take an object and apply the validation function to each value based on the keys. My attempt is as follows:
const validateInput = data => {
let errors = {};
const keys = Object.keys(data);
keys.map(key => {
const error = val[key](data[key]);
errors = { ...errors, ...error };
});
return errors;
};
I get this error:
TypeError: val[key] is not a function
However, the following executes successfully:
const validateInput = data => {
let errors = {};
const test = "firstName";
const errors = {...errors, ...val[test](data[test])};
return errors;
};
When I log keys I get an array of strings and when I log typeof key I also get string, so I don't understand why it will not work within the map function.
Thanks in advance.
Thanks to Jonas above I was able to figure it out. I'm comparing two fields (password and password2) inside of one function. The following code works:
const validateInput = data => {
let errors = {};
const keys = Object.keys(val);
keys.map(key => {
let error;
if (data.hasOwnProperty(key)) {
switch (key) {
case "password":
error = val[key](data[key], data[`${key}2`]);
break;
default:
error = val[key](data[key]);
break;
}
errors = { ...errors, ...error };
}
});
return { errors, isValid: isEmpty(errors) };
};

Categories

Resources