Promises resolving in wrong order - javascript

I am playing with promises and modified a script from Medium.
When I run the script it prompts for the code then displays the json data before I can input a value. I then input a value without the prompt for the script to exit.
How can I get the input before the API call works?
'use strict'
const request = require('request')
const readline = require('readline')
let userDetails
const getInput = prompt => new Promise( resolve => {
const io = { input: process.stdin, output: process.stdout }
const read = readline.createInterface(io)
read.question(`${prompt}: `, data => {
console.log(data)
read.close()
resolve(data)
})
})
const getData = () => new Promise( (resolve, reject) => {
const options = {
url: 'https://api.github.com/users/marktyers',
headers: {
'User-Agent': 'request'
}
}
// Do async job
request.get(options, (err, resp, body) => {
if (err) reject(err)
else resolve(JSON.parse(body))
})
})
function main() {
const GitHubAPICall = getData()
const getBase = getInput('input base currency')
GitHubAPICall
.then(result => {
userDetails = result
console.log('Initialized user details')
console.log(userDetails)
}).then(getBase)
.catch(err => console.log(err))
}
main()

In your main function, you can do it like that:
function main() {
const GitHubAPICall = getData; // WITHOUT ()
const getBase = getInput; // Those 2 declarations are useless, btw
GitHubAPICall()
.then(result => {
userDetails = result
console.log('Initialized user details')
console.log(userDetails)
})
.then(() => getBase())
.then(data => // Do something with the data returned by 'getInput')
.catch(err => console.log(err))
}

Related

How to mock https.get with Jest

I have a function that calls https.get inside a promise which I want to test with Jest.
The function is like this:
const request = (url) => {
return new Promise((resolve, reject) => {
const chunks = [];
https.get(url, (stream) => {
stream
.on('data', (chunk) => {
if( chunk ) {
chunks.push(JSON.parse(chunk));
}
})
.on('error', (err) => {
reject(err);
})
.on('end', () => {
const data = doSomething(chunks);
resolve(data)
});
});
})
}
I want to test that when the function resolves on "end" and rejects on "error";
Currently I have a test like this but because .on("end") doesn't get called, the promise never resolves.
describe("request", () => {
it("Should resolve", async (done) => {
const response = await request("my-url");
expect(response).toEqual("some-data")
})
})
How can I mock events like .on("end") to be called and ensure the promise resolves?
You can do something like this.
// ./request.test.js
jest.mock('https', () => ({
methodToMock: {}
}));
const Stream = require('stream');
const request = require("./request");
const httpsMock = require("https");
describe("request", () => {
it("Should resolve", async () => {
var streamStream = new Stream()
httpsMock.get = jest.fn().mockImplementation((url, cb) => {
cb(streamStream)
streamStream.emit('data', 'some');
streamStream.emit('data', '-');
streamStream.emit('data', 'data');
streamStream.emit('end'); // this will trigger the promise resolve
})
const response = await request("my-url");
expect(response).toEqual("some-data");
})
})
const https = require("https");
const request = (url) => {
return new Promise((resolve, reject) => {
const chunks = [];
https.get(url, (stream) => {
stream
.on('data', (chunk) => {
if (chunk) {
// chunks.push(JSON.parse(chunk));
chunks.push(chunk);
}
})
.on('error', (err) => {
reject(err);
})
.on('end', () => {
// const data = doSomething(chunks);
const data = chunks.join('');
resolve(data)
});
});
})
}
module.exports = request;
Note that jest.mock('https', ...) need to be called before const request = require("./request"); if you want https to be mocked.

Need help testing promise chains using jest

I have a function that looks like the following:
const func = () =>
new Promise((resolve, reject) =>
asyncFunc()
.then(data =>
axios.post('someAPI', {
data
})
)
.then(response => {
asyncFunc1(response.data)
resolve(response.data)
})
.catch(err => reject(err)
);
I have read through the documentation of jest and mocking async functions, but it does not seem to cover the scope of this function. Can someone provide some insight into testing functions of this complexity?
EDIT:
Here is the function and current testing:
export const refreshAuth = () =>
new Promise((resolve, reject) =>
getRefreshToken()
.then(refreshJWT =>
axios.post(`${SomeAPI.auth}/refresh`, {
refreshJWT
})
)
.then((res: AxiosResponse<JWTData>) => {
onSignIn(res.data.accessJWT, res.data.refreshJWT);
resolve(res.data.accessJWT);
})
.catch(err => {
console.error('failed to refresh the access token', err);
reject(err);
})
);
export const onSignIn = (access: string, refresh: string) =>
Promise.all([
SecureStore.setItemAsync(REFRESH_KEY, refresh),
SecureStore.setItemAsync(ACCESS_KEY, access)
]);
export const getRefreshToken = () => SecureStore.getItemAsync(REFRESH_KEY);
And Testing:
describe('OAuth2', () => {
it('Runs all promise chains within refreshAuth()', async done => {
const data = {
data: {
accessJWT: 'token',
refreshJWT: 'refresh'
}
};
const getItemAsync = jest.fn().mockResolvedValue({ refreshToken: 'refresh' });
const mockOnSignIn = jest.fn().mockResolvedValue({});
const mockPostAxios = mockedAxios.post.mockResolvedValue(data);
return OAuth2.refreshAuth().then(() => {
expect(getItemAsync).toHaveBeenCalled();
expect(mockPostAxios).toHaveBeenCalled();
expect(mockOnSignIn).toHaveBeenCalledWith(
data.data.accessJWT,
data.data.refreshJWT
);
});
});
});

JS read file onload returns undefined

I want to read a TXT file from a directory, I have this code which works fine
window.onload = () => {
fetch("file.txt")
.then(res => res.text())
.then(data => {
console.log(data);
});
};
But I want to exe the fetch call in a function like so:
window.onload = () => {
const filePath = "file.txt";
const fileData = readDataFile(filePath);
console.log(fileData);
};
const readDataFile = path => {
fetch(path)
.then(res => res.text())
.then(data => {
return data;
});
};
But in this case, it returns undefined.
Another problem with it, is I can't catch if an error occurs, I tried adding catch to the promise and throw an error but it does not work. This is what I've tried:
window.onload = () => {
fetch("file.txt")
.then(res => res.text())
.then(data => {
console.log(data);
})
.catch(err => {
throw new Error("ERROR!");
});
};
THANKS :)
This works:
const readDataFile = async path => {
try {
const response = await fetch(path);
const data = await response.text();
return data;
} catch (err) {
console.log('Cannot read file.');
}
}
window.onload = async () => {
const filePath = 'data.txt';
const fileData = await readDataFile(filePath);
console.log(fileData);
}
But again, the catch method does not work ? am I doing it wrong ?

data output after receiving it in fetch

I apologize for the stupid question, please tell me how to transfer data from fetch (). then () to another function.
const http = require('http');
const https = require('https');
var urlZaprosHttp = 'http://ietf.org/';
var urlZaprosHttps = 'https://ietf.org/';
const fetch = url => new Promise((resolve, reject) => {
const protocol = url.startsWith('https') ? https : http;
protocol.get(url, res => {
if (res.statusCode !== 200) {
const { statusCode, statusMessage } = res;
reject(new Error(`Status Code: ${statusCode} ${statusMessage}`));
}
res.setEncoding('utf8');
const lines = [];
res.on('data', chunk => lines.push(chunk));
res.on('end', () => resolve(lines.join()));
});
});
// Usage
fetch(urlZaprosHttps)
.then(body => console.log(body))
.catch(err => console.error(err));
You can just simply call another function from within then() and do whatever you want with your data in that function:
fetch(urlZaprosHttps)
.then(body => someOtherFunction(body))
.catch(err => console.error(err));
const myFunc = (data) => {
console.log(data)
}
fetch(urlZaprosHttps)
.then(myFunc(data))
.catch(err => console.error(err));
In the then you can pass in a function and the data returned will be passed to that function, like in my example.

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