Object "undefined" in Mocha script. Not sure how to pass on value - javascript

I am running a mocha test on a bunch of endpoints and I'm not able to pass on results to the next test case
Failing at line var result = data["results"];
error:data undefined
it('should get series', async () => {
let data = await legacy.getCategories(config[process.env.TEST_ENV].url, config[process.env.TEST_ENV].origin);
console.log(data);
expect(data).to.be.an('array').that.is.not.empty;
done();
});
var unallowedGuids = config[process.env.TEST_ENV].unallowedGuids;
var result = data["results"];
for (i = 0; i < result.length; i++) {
let guid = result[i]["guid"];
let showName = result[i]["title"];
if (!unallowedGuids.includes(guid)){
it('should get colletions guid', async () => {
let data = await legacy.collectionsGuid(config[process.env.TEST_ENV].url, config[process.env.TEST_ENV].origin, guid);
expect(data).to.be.an('array').that.is.not.empty;
done();
});
it('should get series guid', async () => {
let data = await legacy.seriesGuid(config[process.env.TEST_ENV].url, config[process.env.TEST_ENV].origin, guid);
expect(data).to.be.an('array').that.is.not.empty;
done();
});
}
else
console.log("excluded", guid);
}
});```

I think your issue is related to variable scope.
Try modifying your code like so:
let data; // initialize "data" outside of the "it" callback function
it('should get series', async () => {
data = await legacy.getCategories(config[process.env.TEST_ENV].url, config[process.env.TEST_ENV].origin);
console.log(data);
expect(data).to.be.an('array').that.is.not.empty;
done();
});
var unallowedGuids = config[process.env.TEST_ENV].unallowedGuids;
var result = data["results"]; // data will be defined here

For your case, you got undefined because var result = data["results"]; is executed first before your it('should get series', ..) function.
One solution is to restructure the test to make sure the order of execution is correct. We can use before() or beforeEach() For example:
let data;
before(async () => {
data = await legacy.getCategories(config[process.env.TEST_ENV].url, config[process.env.TEST_ENV].origin);
});
it('get collection and series guid', async function() {
var unallowedGuids = config[process.env.TEST_ENV].unallowedGuids;
var result = data["results"]; // it will be executed after data is fetched in `before()`
for (i = 0; i < result.length; i++) {
let guid = result[i]["guid"];
let showName = result[i]["title"];
if (!unallowedGuids.includes(guid)){
let data = await legacy.collectionsGuid(config[process.env.TEST_ENV].url, config[process.env.TEST_ENV].origin, guid);
expect(data).to.be.an('array').that.is.not.empty;
let data = await legacy.seriesGuid(config[process.env.TEST_ENV].url, config[process.env.TEST_ENV].origin, guid);
expect(data).to.be.an('array').that.is.not.empty;
}
else {
console.log("excluded", guid);
}
}
});
Alternatively, you also can put the data fetching in same it() function
// no before()
it('get collection and series guid', async function() {
var unallowedGuids = config[process.env.TEST_ENV].unallowedGuids;
var data = await legacy.getCategories(config[process.env.TEST_ENV].url, config[process.env.TEST_ENV].origin);
var result = data["results"];
....
});
Hope it helps

Related

Fetch values from Firestore and store the output as global using async

I am trying to fetch the firestore data and then store it in a variable
async function getchildContent(Parent, Message) {
let count = 0;
var db = firebase.firestore();
var output = db.collection("rooms").doc(Parent).collection("messages").where("ParentId", "==", Message).get().then(function (querySnapshot) {
querySnapshot.forEach(function (doc) {
})
});
return output;
}
This function i am calling as
var dataAll ={};
getchildContent(PDocId, doc.id).then(result=>{
dataAll = result;
});
console.log(dataAll);
If i assign it as
var output = getchildContent(PDocId, doc.id);
Then the result will br promise {pending}
But I am getting an empty array output, How to resolve this?
You should handle the promises using either a promise chain or async-await. It seems you want to use async await syntax so try this:
async function getchildContent(Parent, Message) {
let count = 0 ;
const db = firebase.firestore();
const querySnapshot = await db.collection("rooms").doc(Parent).collection("messages").where("ParentId","==",Message).get()
const data = querySnapshot.map.docs((doc) => doc.data())
return data
});
// This should be inside of an async function as you need to use await.
const output = await getchildContent(PDocId, doc.id);
// If you are using promise chainging
let output = null
getchildContent(PDocId, doc.id).then((data) => {
console.log(data)
output = data
// logging output here will log the value
// proceed code execution within then block
})
// If you log output here, it'll be null as then promise above will not be resolved

Promise in background sync

I have a promise which return an array of objects from IndexedDB:
const syncData = () => {
return new Promise((resolve, reject)=>{
var all_form_obj = [];
var db = self.indexedDB.open('Test');
db.onsuccess = function(event) {
var db = this.result
// Table new_form
var count_object_store_new_form = this.result.transaction("new_form").objectStore("new_form").count()
count_object_store_new_form.onsuccess = function(event) {
if(count_object_store_new_form.result > 0){
db.transaction("new_form").objectStore("new_form").getAll().onsuccess = function(event) {
var old_form_arr = event.target.result
for(element in old_form_arr){
all_form_obj.push(old_form_arr[element])
}
}
}
}
// Table old_form
var count_object_store_old_form = this.result.transaction("old_form").objectStore("old_form").count()
count_object_store_old_form.onsuccess = function(event) {
if(count_object_store_old_form.result > 0){
db.transaction("old_form").objectStore("old_form").getAll().onsuccess = function(event) {
var old_form_arr = event.target.result
for(element in old_form_arr){
all_form_obj.push(old_form_arr[element])
}
}
}
}
}
db.onerror = function(err) {
reject(err);
}
resolve(all_form_obj)
})
};
After I resolve my array, I call the promise in the sync event:
self.addEventListener('sync', function(event) {
if (event.tag == 'sync_event') {
event.waitUntil(
syncData()
.then((form_arr)=>{
console.log(form_arr)
for(form in form_arr) {
console.log(form_arr)
}
}).catch((err) => console.log(err))
);
}
});
In the 'then' of my promise syncData I print to the console two times.
The first console.log appears in the console (my array of objects) but the second which is in loop (for in) doesn't appear in the console and I don't understand why.
My goal is to be able to loop through each object and send it to my database with fetch but the problem is that the code in the loop doesn't run.
My result of the first console log:
I think resolve is not placed in the desired place and the reason why the 2nd console.log is not showing up is because form_arr is []. I simplified your code to demonstrate why it went []. db.onsuccess and db.onerror were just defined there without being called. To fix this problem, you may want to place resolve inside db.onsuccess and reject inside db.onerror.
const syncData = () => {
return new Promise((resolve, reject)=>{
var all_form_obj = [];
var db = self.indexedDB.open('Test');
db.onsuccess = function(event) {
// ... will be called async
resolve(all_form_obj)
}
db.onerror = function(err) {
// ... will be called async
}
// remove resolve here
})
};

async api call function seems to work until test

I am trying to get some exchange data and use it for some logic. I thought the most straight forward idea would be to use a function where I could pass the different pairs I may want, there are many per exchange. If I console log inside the function when the data ends everything works find. When i try and get the response when it is ready I get undefined, please see the commented console log and my last line.
I understand that I am missing something with async and the way it works.
const https = require('https');
async function binancePairPrice (binancePair) {
let url = 'https://api.binance.com/api/v3/ticker/bookTicker';
let queryString = '?symbol='
https.get(url+queryString+binancePair,(res) => {
console.log(res.statusCode);
let binanceBookTicker = '';
let binanceBookTickerJson =
res.on('data', data => {
binanceBookTicker += data;
});
res.on('end', () => {
binanceBookTickerJson = JSON.parse(binanceBookTicker);
//console.log(binanceBookTickerJson);
return (binanceBookTickerJson)
});
});
};
binancePairPrice('BTCUSDT').then(console.log);
day one javascript coming from python. This is quite a step from what I am used to writing. Any docs or links would be appreciated too.
thansk
https.get doesn't return something that can be promisified, so you can't await it.
You can do something else which is wrapping the https.get call within a Promise and then await it when calling binancePairPrice.
const https = require('https')
async function binancePairPrice (binancePair) {
let url = 'https://api.binance.com/api/v3/ticker/bookTicker';
let queryString = '?symbol='
return new Promise((resolve) => {
https.get(url, res => {
let binanceBookTicker = '';
let binanceBookTickerJson =
res.on('data', data => {
binanceBookTicker += data;
});
res.on('end', () => {
resolve() = >
{
binanceBookTickerJson = JSON.parse(binanceBookTicker);
return (binanceBookTickerJson)
}
});
})
})
}
(async () => await binancePairPrice('BTCUSDT))()
Your binancePairPrice function doesn't wait for the end callback to happen and therefore just carries on and returns undefined.
You need to return a Promise and then resolve the promise with the value you want to return from the function.
Promise basics
Using the Promise() constructor
async function binancePairPrice (binancePair) {
return new Promise((resolve, reject) => {
let url = 'https://api.binance.com/api/v3/ticker/bookTicker';
let queryString = '?symbol=';
https.get(url+queryString+binancePair,(res) => {
console.log(res.statusCode);
let binanceBookTicker = '';
let binanceBookTickerJson =
res.on('data', data => {
binanceBookTicker += data;
});
res.on('end', () => {
binanceBookTickerJson = JSON.parse(binanceBookTicker);
//console.log(binanceBookTickerJson);
resolve(binanceBookTickerJson)
});
});
});
}

How to change variable value in Axios response?

I'm trying to change a variable value in axios's then. Here is my example:
var pts = [];
axios.get('http://www.example.com')
.then(function (response) {
pts = response.data;
});
console.log(pts);
The pts variable just returns empty array. I just want to use it out of the GET query. How can I change it?
use the new elegant way async & await it is more neat and readable
let pts = [];
const getData = async () => {
const {data} = await axios.get("http://www.example.com");
pts = data;
return data
}
getData();
console.log(pts);
The request is asynchronous so the pts gets printed first and then the function gets called
What you can do is use a promise and make your request as follows:
const func1 = () => {
return axios.get("http://www.example.com").then(response => {return response})
}
func1().then(data => {
pts = data;
})

loadData() returning empty array

I'm trying to return an array of objects to a function, and looking at the debugger, it looks like it just returns an empty array.
Here's the function that I'm hoping to use:
// load from json file
loadData(filepath) {
let rooms = [];
fetch(filepath)
.then(
res => res.json()
)
.then(function (data) {
// console.log(data);
for (let i = 0; i < data.rooms.length; i++) {
rooms.push(data.rooms[i]);
}
});
return rooms;
}
I go into the debugger, and I see the rooms from data.rooms getting pushed to my local rooms object, but when I get back up to my init() function that's supposed to use this rooms data:
let rooms = this.loadData(this.datapath); // TODO: make games load from json data
for (let i = 0; i < rooms.length; i++) {
this.addRoom(rooms[i].name, rooms[i].getText, rooms[i].prompts, rooms[i].requirements);
}
It looks like it's passed an empty array. Is there a scoping issue or something I'm missing? I'm not very experienced with fetch/promises/JSON.
Happy to provide any further info that may be useful. Thanks!
The problem is that your local variable rooms will be returned before the async fetch finish.
You can just simple await the fetch statements and make the function async:
async loadData(filepath) {
let rooms = [];
const response = await fetch(filepath);
const data = await response.json();
console.log(data);
for (let i = 0; i < data.rooms.length; i++) {
rooms.push(data.rooms[i]);
}
return rooms;
}
let rooms = await this.loadData(this.datapath);
Try this, if it did not work let me know.
// load from json file
async function call() {
const loadData = async filepath => {
let rooms = [];
return await fetch(filepath)
.then(res => res.json())
.then(async data => {
rooms = await [...data];
return rooms;
});
};
let x = await loadData("https://jsonplaceholder.typicode.com/posts");
console.log("TEST: ", x);
}
call();

Categories