Promise { <pending> } - for last async function - javascript

I have two main functions. The first one gets the SOAP data from an API. The second one parses it to json and then formats it into the object I need to store. I have been logging and seeing the return values, and as of so far until now, it's been fine. However, I am calling exports.createReturnLabelfrom my test file and all I can see is Promise { <pending> } . I am returning a value at the last function. Does this code look weird to your? How can I clean it up?
const soapRequest = require('easy-soap-request');
const xmlParser = require('xml2json')
exports.createReturnLabel = async () => {
const xml = hidden
const url = 'https://ws.paketomat.at/service-1.0.4.php';
const sampleHeaders = {
'Content-Type': 'text/xml;charset=UTF-8',
};
const auth = async () => {
const {
response
} = await soapRequest({
url: url,
headers: sampleHeaders,
xml: xml,
timeout: 2000
});
const {
body,
statusCode
} = response;
return body
}
const fetchLabel = async () => {
const soapData = await auth();
try {
const json = xmlParser.toJson(soapData)
const labelData = JSON.parse(json)["SOAP-ENV:Envelope"]["SOAP-ENV:Body"]["ns1:getLabelResponse"]
return {
courier: 'dpd',
tracking_number: labelData["return"]["paknr"],
barCode: labelData["return"]["barcodecontent"],
printLabel: labelData["return"]["label"],
_ref: null
}
} catch (e) {
return (e)
}
}
return fetchLabel()
}
calling from my test file return console.log(file.createReturnLabel())

There's an async function call inside your code.
Should be: return await fetchLabel(), so that it awaits for completion before going on its merry way.

Related

useQuery always returning undefined data in react-query

I'm new to react-query and I'm trying to move all of my API calls into a new file, out of the useQuery calls.
Unfortunately when I do this all of my data is undefined.
I do see the network calls in the network tab, it just isn't being set properly in useQuery.
Thanks in advance for any help on how to change my code to fix this!
// this works
const { loading, data, error } = useQuery([conf_id], async () => {
const { data } = await axios.get(API_URL + '/event/' + conf_id)
return data
});
// this doesn't work - data is undefined
const axios = require('axios');
const getEventById = async () => {
const { data } = await axios.get(API_URL + '/event/2541' + '?noyear=true');
return data.data;
};
const { loading, data, error } = useQuery('conf_id', getEventById});
// the below variants don't work either
// const { loading, data, error } = useQuery('conf_id', getEventById()});
// const { loading, data, error } = useQuery('conf_id', async () => await getEventById()});
// const { loading, data, error } = useQuery('conf_id', async () => await
// const { data } = getEventById(); return data
// });
An AxiosResponse has a data attribute from which you can access the actual API JSON response.
Like you pointed out, this:
async () => {
const { data } = await axios.get(API_URL + '/event/' + conf_id)
return data
}
Should suffice for the fetching function.
So the final implementation should look like
const axios = require('axios');
const getEventById = async () => {
const { data } = await axios.get(API_URL + '/event/2541' + '?noyear=true');
return data;
};
const { loading, data, error } = useQuery('conf_id', getEventById);
The data you get from the useQuery should be undefined on the first render and once the server responds it will change to whatever the response is.

Jest Fetch reference error: UnhandledPromiseRejection when running a test suite not containing fetch

I have a couple of files below: When I run jest I get this error:
[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "ReferenceError: fetch is not defined".]
ApiHandler.test.ts
import { formatDateOptions } from "/ApiHandler";
describe("formatDateOptions()", () => {
it("Describe bla bla", () => {
const inputDate = {Tables[{a:1}]}
const expected = [ {key:1,text:"a",}]
const result = formatDateOptions(inputDate);
expect(result).toEqual(expected);
});
});
ApiHandler.ts
export const formatDateOptions = (data) => {
const dates = [];
data.Tables[0].Rows.map((x) => dates.push({ key: x[0], text: x[0] }));
return dates;
};
Even though fetch is not being used here, I am getting the above error.For more info, fetch is being used totally unrelated before formatDateOptions is being called
Sample where fetch is being used
ApiHandler.ts (same file)
export const setDatePickerOptions = async()=> {
try {
const [dates, platformSignal] = await Promise.all([
dateFilters(platform),
platformSignal(platform),
]);
try {
const [datesJson, platformSignalJson] = await Promise.all([
dates.json(),
platformSignal.json(),
]);
const responseData = formatDateOptions(datesJson);
} catch (e) {
console.error(e);
}
} catch (e) {
console.error(e);
}
};
export const dateFilters = async(platform)=> {
try {
const dates = await fetchWrapper(platform);
return dates;
} catch (error) {
console.log(error);
}
};
export async function fetchWrapper(platform){
try {
const response = await fetch(url, {
method: "post",
headers,
body: JSON.stringify({
csl: platform
}),
});
return response;
} catch (e) {
console.log(e);
}
}
I even imported node-fetch in APihandler.ts but still that is not working. Please help me.

How should I return data

I'm trying to understand and implement simple app. I've got two express servers, first is only sending plain object and the second is fetching it.
Inside the second app I want to build a class - Loader, that will provide fetch and get (data) methods.
class Loader{
constructor(){
this.data = {data:"some data"}
}
async fetchData(){
const res = await axios.get("http://localhost:5000/data");
if(res) {
this.data = res.data
console.log(this.data)
return res.data
}
}
getData(){
return this.data
}
async getFetchedData(){
await this.fetchData();
console.log(this.data)
this.getData();
}
}
But actually it doesn't work the way I wanted it. I'd like to implement method that will return fetched object.
const testLoader = new Loader();
testLoader.getFetchedData();
const testVar = testLoader.getData();
console.log("test", testVar)
The output is:
test { data: 'some data' }
data from fetchData { data: 'test data after fetching' }
data from getFetchedData { data: 'test data after fetching' }
And I understand - getData is sync and the rest methods are async, so that's the order of perform. But how do I need to rewrite code to receive method that will return the fetched object?
You'll need to await for any async methods to complete (or then-chain them) wherever you use them.
const testLoader = new Loader();
await testLoader.fetchData();
const testVar = testLoader.getData();
console.log("test", testVar)
you can try some code i made
class Loader{
constructor(){
this.data = {data:"some data"}
}
async fetchData(){
const res = await axios.get("http://localhost:5000/data");
this.data = res.data
}
getData(){
return this.data
}
async getFetchedData(){
await this.fetchData();
console.log(this.data)
return this.getData();
}
}
// 1
const exec = async () => {
try {
const loader = new Loader()
await loader.fetchData()
console.log(loader.getData())
} catch(e) {
console.log("ERROR", e)
}
}
exec()
// 2
const exec = async () => {
try {
const loader = new Loader()
const data = await loader.getFetchedData()
console.log(data)
} catch(e) {
console.log("ERROR", e)
}
}
exec()
// 3
const loader = new Loader()
loader.fetchData().then(() => {
console.log(loader.getData())
}).catch((e) => {
console.log("ERROR", e)
})
// 4
const loader = new Loader()
loader.getFetchedData().then((data) => {
console.log(data)
}).catch((e) => {
console.log("ERROR", e)
})

Function with fetch returns undefined instead an array (React Native)

I have a file with some functions:
const API = {
async getComments() {
var data = [];
var url = 'http://url.com/wp-json/wp/v2/comments';
const serviceResponse = await fetch(
url,
)
.then((serviceResponse) => {
return serviceResponse.json();
} )
.catch((error) => console.warn("fetch error:", error))
.then((serviceResponse) => {
for (i in serviceResponse) {
data.push({
"key": serviceResponse[i]['id'].toString(),
"name": serviceResponse[i]['author_name'],
"content": serviceResponse[i]['content']['rendered'].replace(/<(.|\n)*?>/g, ''),
"gravatar": serviceResponse[i]['author_avatar_urls']['96'],
"date": serviceResponse[i]['date'].replace('T', ' ')
});
}
global.comments = data;
return data;
});
}
}
export { API as default }
In another file I include the file, and make the call:
var comments = await API.getComments(key);
console.log (comments);
But I receive undefined, I tried to create a function with bind:
this.newGetComments = API.getComments.bind(this); with the same result. I used a global variable, but I want to remove the globals vars.
/* Few suggestions;
1. you are not returning anything from the getComments method. Please return fetch(url) response.
2. you should return something from the catch block to handle the error.
*/
const API = {
async getComments() {
var url = 'http://url.com/wp-json/wp/v2/comments';
var response = await fetch(url)
.then(serviceResponse => {
return serviceResponse.json();
})
.then(serviceResponse => {
let data = [];
// rest of your code.
return { success: true, data };
})
.catch(error => {
console.warn('fetch error:', error);
return { success: false, error };
});
return response
},
};
var comments = await API.getComments(key);
if (comments.success) {
// handle the success case comments.data
} else {
// handle the Error case comments.error
}
console.log(comments);
An async function always returns a promise as you aren't returning anything from the getComments methods, the function automatically resolves and returns undefined(Promise.resolve(undefined)). You need to return serviceResponse from the getComments method to get the fetch api's response.
You can try something like below:
async componentDidMount() {
let data = [];
const result = await this.getComments();
const jsonData = await result.json();
console.log('Result ==> ', jsonData.serviceResponse);
jsonData.serviceResponse.map(data =>
data.push({
"key": data['id'].toString(),
"name": data[i]['author_name'],
"content": data[i]['content']['rendered'].replace(/<(.|\n)*?>/g, ''),
"gravatar": data[i]['author_avatar_urls']['96'],
"date": data[i]['date'].replace('T', ' ')
})
);
console.log('Data ==> ', data);
}
async getComments() {
const result = await fetch('http://url.com/wp-json/wp/v2/comments', {method: 'GET'});
return result;
}

Node.js - Mock result of a promise

I want to mock the result of a function within a node module so that i can run assertions.
Considering the following node module:
const doPostRequest = require('./doPostRequest.js').doPostRequest;
const normalizeSucessResult = require('./normalizer.js').normalizeSucessResult;
const normalizeErrorResult = require('./normalizer.js').normalizeErrorResult;
exports.doPost = (params, postData) => {
return doPostRequest(params, postData).then((res) => {
const normalizedSuccessResult = normalizeSucessResult(res);
return normalizedSuccessResult;
}).catch((err) => {
const normalizedErrorResult = normalizeErrorResult(err);
return normalizedErrorResult;
})
}
The function doPostRequest returns a promise. How can i fake the return value of this promise so that i can assert if normalizeSucessResult has been called?
So for i have tried:
const normalizeSucessResult = require('./normalizer.js');
const doPostRequest = require('./doPostRequests.js');
const doPost = require('./doPost.js');
it('runs a happy flow scenario', async () => {
let normalizeSucessResultStub = sinon.stub(normalizeSucessResult, 'normalizeSucessResult');
let postData = { body: 'Lorum ipsum' };
let params = { host: 'someUrl', port: 433, method: 'POST', path: '/' };
sinon.stub(doPostRequest, 'doPostRequest').resolves("some response data"); //Fake response from doPostRequest
return doPost.doPost(params, postData).then((res) => { //res should be equal to some response data
expect(normalizeSucessResultStub).to.have.been.calledOnce;
expect(normalizeSucessResultStub).to.have.been.with("some response data");
});
});
The doPostRequest module looks like this:
const https = require('https')
module.exports.doPostRequest = function (params, postData) {
return new Promise((resolve, reject) => {
const req = https.request(params, (res) => {
let body = []
res.on('data', (chunk) => {
body.push(chunk)
})
res.on('end', () => {
try {
body = JSON.parse(Buffer.concat(body).toString())
} catch (e) {
reject(e)
}
resolve(body)
})
})
req.on('error', (err) => {
reject(err)
})
if (postData) {
req.write(JSON.stringify(postData))
}
req.end()
})
}
You can use Promise.resolve to return a promise with any given value.
Promise.resolve(“hello world”);
For stub your func you need to do like this
sinon.stub({doPostRequest}, 'doPostRequest').resolves("some response data")
Okay, i figured it out. The function doPostRequest was loaded using require, on the top of the file using const doPostRequest = require('./doPostRequest.js').doPostRequest;
In order to mock the data that comes back from a function that is loaded using require i had to use a node module called mock-require. There are more modules that can take care of this (proxyquire is a populair one) but i picked mock-require (i did not have a specific reason for choosing mock-require).
For anyone else that is stuck with a similar problem, try mock-require to mock the respose from files that are loaded using require.

Categories