How can I do Jest API test for this code? - javascript

I have tried several ways for mocking this unit of my code but still, it doesn't work. I'm using create-react-app and jest for testing.
I have a function in admin adminSignup.js for sending data to my server(Node.js and Mongoose) for creating account:
/* eslint-disable no-undef */
function signup(user, cb) {
return fetch(`signup`, {
headers: {"Content-Type": "application/json"},
method: "POST",
body:JSON.stringify({
username: user.username,
email: user.email,
password: user.password,
picode: user.pincode,
building: user.building,
city: user.city,
state: user.state
}),
})
.then(checkStatus)
.then(parseJSON)
.then(cb)
.catch(err => console.log(err));
}
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
}
const error = new Error(`HTTP Error ${response.statusText}`);
error.status = response.statusText;
error.response = response;
console.log(error); // eslint-disable-line no-console
throw error;
}
function parseJSON(response) {
return response.json();
}
const adminSignup = { signup };
export default adminSignup;
and I have called this in my component(RegisterPage.jsx) :
adminSignup.signup( user, response => {
this.setState({response: response});
console.log(response);
});
Now I want to write a mock for my signup call(adminSignup.js). But just wonder how can I do this?
I have tried Jest Fetch Mock for mock testing(it doesnt need to create mock file) and it's working but I'm not quite sure is it correct or no :
describe('testing api', () => {
beforeEach(() => {
fetch.resetMocks();
});
it('calls signup and returns message to me', () => {
expect.assertions(1);
fetch.mockResponseOnce(JSON.stringify('Account Created Successfully,Please Check Your Email For Account Confirmation.' ));
//assert on the response
adminSignup.signup({
"email" : "sample#yahoo.com",
"password" : "$2a$0yuImLGh1NIoJoRe8VKmoRkLbuH8SU6o2a",
"username" : "username",
"pincode" : "1",
"city" : "Sydney",
"building" : "1",
"state" : "NSW"
}).then(res => {
expect(res).toEqual('Account Created Successfully,Please Check Your Email For Account Confirmation.');
});
//assert on the times called and arguments given to fetch
expect(fetch.mock.calls.length).toEqual(1);
});
});
I really like to create a mock file and test with that but reading jest website is not working for me.
Thanks in advance.

I have found this way(using mock-http-server) for another POST request and it works for me:
userList.js:
async function getUser (id, cb) {
const response = await fetch(`/getUserById/${id}`, {
// headers: {"Content-Type": "application/json"},
method: "POST",
body:JSON.stringify({
id : id
}),
})
.then(checkStatus)
.then(parseJSON)
.then(cb)
.catch(err => console.log(err));
const user = response.json();
return user;
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
}
const error = new Error(`HTTP Error ${response.statusText}`);
error.status = response.statusText;
error.response = response;
console.log(error); // eslint-disable-line no-console
throw error;
}
function parseJSON(response) {
return response.json();
}
}
userList.test.js:
import ServerMock from "mock-http-server";
import userLists from '../components/UserList/userLists';
describe('Test with mock-http-server', function() {
// Run an HTTP server on localhost:3000
var server = new ServerMock({ host: "localhost", port: 3000 });
beforeEach(function(done) {
server.start(done);
});
afterEach(function(done) {
server.stop(done);
});
it('should do something', function(done) {
var id = 4;
server.on({
method: 'POST',
path: `/getUserById/${id}`,
reply: {
status: 200,
headers: { "content-type": "application/json" },
body: JSON.stringify({ id: 4 })
}
});
// Now the server mock will handle a GET http://localhost:3000//getUserById/${id}
// and will reply with 200 `{"id": 4}`
function cb(data) {
console.log(data);
expect(data).toBe({name:'Bob'});
done();
}
const response = userLists.getUser(4, cb);
console.log(response);
done();
});

Related

Ho to make 404 error alert in axios react

Hello how can realize 404 error in axios?
Here's my code
const WeatherFunc = async (city) => {
const { data } = await axios.get(url, {
params: {
q: city,
units: 'metric',
APPID: apikey,
}
});
return data;
}
Check the response status in the axios promise
axios.get(url, {
//...
}).then(response => {
if (response.status === 404) {
// handle your 404
}
// ...
}).catch(error => {
// handle server error..
})

Nodejs async loop function returns blank [duplicate]

I'm doing requests to my API server to authenticate a user, that's not the problem. The problem is that I don't know why my async function doesn't return anything, and I get an error because the data that I want from this function is undefined.
Don't worry if the error management is ugly and in general I can do this better, I'll do that after fixing this problem.
Utils.js class
async Auth(username, password) {
const body = {
username: username,
password: password
};
let req_uuid = '';
await this.setupUUID()
.then((uuid) => {
req_uuid = uuid;
})
.catch((e) => {
console.error(e);
});
let jwtData = {
"req_uuid": req_uuid,
"origin": "launcher",
"scope": "ec_auth"
};
console.log(req_uuid);
let jwtToken = jwt.sign(jwtData, 'lulz');
await fetch('http://api.myapi.cc/authenticate', {
method: 'POST',
headers: { "Content-Type": "application/json", "identify": jwtToken },
body: JSON.stringify(body),
})
.then((res) => {
// console.log(res);
// If the status is OK (200) get the json data of the response containing the token and return it
if (res.status == 200) {
res.json()
.then((data) => {
return Promise.resolve(data);
});
// If the response status is 401 return an error containing the error code and message
} else if (res.status == 401) {
res.json()
.then((data) => {
console.log(data.message);
});
throw ({ code: 401, msg: 'Wrong username or password' });
// If the response status is 400 (Bad Request) display unknown error message (this sould never happen)
} else if (res.status == 400) {
throw ({ code: 400, msg: 'Unknown error, contact support for help. \nError code: 400' });
}
})
// If there's an error with the fetch request itself then display a dialog box with the error message
.catch((error) => {
// If it's a "normal" error, so it has a code, don't put inside a new error object
if(error.code) {
return Promise.reject(error);
} else {
return Promise.reject({ code: 'critical', msg: error });
}
});
}
Main.js file
utils.Auth('user123', 'admin')
.then((res) => {
console.log(res); // undefined
});
Your Async function must return the last promise:
return fetch('http://api.myapi.cc/authenticate', ...);
or await the result and return it:
var x = await fetch('http://api.myapi.cc/authenticate', ...);
// do something with x and...
return x;
Notice that you don’t need to mix promise syntax (.then) with await. You can, but you don’t need to, and probably shouldn’t.
These two functions do exactly the same thing:
function a() {
return functionReturningPromise().then(function (result) {
return result + 1;
});
}
async function b() {
return (await functionReturningPromise()) + 1;
}
await is not to be used with then.
let data = await this.setupUUID();
or
let data=null;
setupUUID().then(res=> data = res)
I would try something like this:
const postReq = async (jwtToken) => {
const body = {
username: username,
password: password,
};
try {
const res = await fetch('http://api.myapi.cc/authenticate', {
method: 'POST',
headers: { "Content-Type": "application/json", "identify": jwtToken },
body: JSON.stringify(body),
})
if (res) {
if (res.status == 200) {
return res.json();
} else if (res.status == 401) {
const data = res.json();
console.log(data.message)
throw ({ code: 401, msg: 'Wrong username or password' });
} else if (res.status == 400) {
throw ({ code: 400, msg: 'Unknown error, contact support for help. \nError code: 400' });
}
}
} catch (err) {
console.error(err)
}
};
const Auth = async (username, password) => {
const jwtData = {
"origin": "launcher",
"scope": "ec_auth"
};
try {
const req_uuid = await this.setupUUID();
if (req_uuid) {
jwtData["req_uuid"] = req_uuid;
const jwtToken = jwt.sign(jwtData, 'lulz');
return await postReq(jwtToken);
}
} catch (err) {
console.error(err);
};
}

AWS Lambda call 3 async functions by 1 Lambda call

Ok, i'm done. Please someone help me :(
I don't know how js and lambda works
What i have to do:
Send GET request and get response.
Write data from response to DynamoDb
I can do it 1by1 but can't do everything by 1 lambda call.
My code:
const https = require('https');
const crypto = require("crypto");
const AWS = require('aws-sdk');
const DynamoDb = new AWS.DynamoDB({region: 'eu-central-1'});
exports.handler = async (event) => {
let response;
console.log("Start");
let steamTicket;
let steamId;
if(event.body){
const body = JSON.parse(event.body);
if(body.steamticket && body.steamid){
steamTicket = body.steamticket;
steamId = body.steamid;
}
else{
response = {
statusCode: 400,
body: JSON.stringify({
authenticated: false,
reason: 'cant find steamid or steamticket in your request'
})
};
return response;
}
}
else{
response = {
statusCode: 400,
body: JSON.stringify({
authenticated: false,
reason: 'cant find request body'
})
};
return response;
}
await httprequest(steamTicket).then((data) =>{
if(data.response && data.response.params){
if(data.response.params.result == 'OK' && data.response.params.steamid == steamId){
console.log(JSON.stringify(data));
const sessionId = crypto.randomBytes(16).toString("hex");
console.log('Generated session id: ' + sessionId);
PutToDB(sessionId, steamId);
}
else{
response = {
statusCode: 400,
body: JSON.stringify({
authenticated: false,
reason: 'steam response is not OK or session != steamId'
})
};
return response;
}
}
else{
response = {
statusCode: 400,
body: JSON.stringify({
authenticated: false,
reason: 'invalid response from steam: ' + JSON.stringify(data)
})
};
return response;
}
});
};
async function PutToDB(sessionId, steamId){
var WriteParams = {
RequestItems:{
SteamSessions: []
}
};
WriteParams.RequestItems.SteamSessions.push({
PutRequest:{
Item: {
SteamId: {S: steamId},
SessionId: {S: sessionId},
ttl: {N: (Math.floor(Date.now() / 1000) + 600).toString()}
}
}
});
console.log('SessionIdToWrite: ' + sessionId);
return new Promise((resolve, reject) =>{
DynamoDb.batchWriteItem(WriteParams, function(err, data){
if(err){
console.log("Error", err);
}
else{
console.log("Success write", JSON.stringify(data));
}
})
})
}
async function httprequest(steamTicket) {
return new Promise((resolve, reject) => {
const options = {
host: 'partner.steam-api.com',
path: '/ISteamUserAuth/AuthenticateUserTicket/v1/?key=somekey&appid=someid&ticket=' + steamTicket,
port: 443,
method: 'GET'
};
const req = https.request(options, (res) => {
if (res.statusCode < 200 || res.statusCode >= 300) {
return reject(new Error('statusCode=' + res.statusCode));
}
var body = [];
res.on('data', function(chunk) {
body.push(chunk);
});
res.on('end', function() {
try {
body = JSON.parse(Buffer.concat(body).toString());
} catch(e) {
reject(e);
}
resolve(body);
});
});
req.on('error', (e) => {
reject(e.message);
});
// send the request
req.end();
});
}
I lost way already, i'm not even sure it should work like that.
And most confusing thing! This b give me this test results:
Run 1:
2021-03-05T13:28:47.741Z INFO Start
2021-03-05T13:28:48.612Z INFO {"response":{"params":{"result":"OK","steamid":"mysteamid","ownersteamid":"mysteamid","vacbanned":false,"publisherbanned":false}}}
2021-03-05T13:28:48.650Z INFO Generated session id: 6a5633a5f862d8663d0fe546a9c89feb
2021-03-05T13:28:48.650Z INFO SessionIdToWrite: 6a5633a5f862d8663d0fe546a9c89feb
DynamoDb is empty, here we can't see log from DynamoDb.batchWriteItem result.
Run 2:
2021-03-05T13:29:53.308Z INFO Start
2021-03-05T13:29:53.674Z INFO Success write {"UnprocessedItems":{}}
2021-03-05T13:29:54.048Z INFO {"response":{"params":{"result":"OK","steamid":"mysteamid","ownersteamid":"mysteamid","vacbanned":false,"publisherbanned":false}}}
2021-03-05T13:29:54.048Z INFO Generated session id: 05c62de782202fc100cea9d47e38242c
2021-03-05T13:29:54.048Z INFO SessionIdToWrite: 05c62de782202fc100cea9d47e38242c
And after second run i can see in DynamoDb sessionId from FIRST RUN (6a5633a5f862d8663d0fe546a9c89feb)
If i run it again, there will be id from 2nd run
I think it continues to run previous tasks on new run? Or what? I'm lost
Thank you for any help with it
You need to call reject / resolve in the DynamoDb.batchWriteItem call.
return new Promise((resolve, reject) =>{
DynamoDb.batchWriteItem(WriteParams, function(err, data){
if(err){
console.log("Error", err);
reject(err);
}
else{
console.log("Success write", JSON.stringify(data));
resolve();
}
})
})

Problem authentification bearer with react native

The connexion is working but when i tried to get information from my DB with the middleware on, i have an error 401. For information, the request works on postman but not on my app.
I think the problem comes from the authentification bearer in my fetch
my middleware :
/* Middleware */
const authentification = (req, res, next) => {
try {
/* decode token and compare, set userID */
const token = req.headers.authorization.split(" ")[1];
const decodedToken = jwt.verify(token, "RANDOM_TOKEN_SECRET");
const userId = decodedToken.userId;
/* if userID in body compare with DB userID, else (no userID in body) it's ok*/
if (req.body.userId && req.body.userId !== userId) {
throw "Invalid user ID";
} else {
User.findOne({ _id: userId }, (err, data) => {
if (err) {
res.status(500).json({
error: new Error("Internal server error"),
});
return;
}
if (!data) {
res.status(404).json({
message: "Erreur d'authentification",
});
return;
}
req.user = data;
next();
});
}
} catch {
res.status(401).json({
message: "Invalid request!",
});
}
};
And my fetch
getClubUser = async () => {
const headers = new Headers({
'Content-type': 'application/json',
Authorization: 'bearer' + (await AsyncStorage.getItem('token')),
});
const options = {
method: 'GET',
headers: headers,
};
fetch('http://localhost:8080/dashboard/clubInfo', options)
.then((response) => {
console.log(response);
return response.json();
})
.then(
(data) => {
this.setState({sport: data});
console.log(this.state.sport.clubs);
},
(err) => {
console.log(err);
},
);
};

Sagas and fetch promises

I've been banging my head on the desk for the last few minutes here due to this API request...
I have the following code:
Saga:
export function * registerFlow () {
while (true) {
const request = yield take(authTypes.SIGNUP_REQUEST)
console.log('authSaga request', request)
let response = yield call(authApi.register, request.payload)
console.log('authSaga response', response)
if (response.error) {
return yield put({ type: authTypes.SIGNUP_FAILURE, response })
}
yield put({ type: authTypes.SIGNUP_SUCCESS, response })
}
}
API request:
// Inject fetch polyfill if fetch is unsuported
if (!window.fetch) { const fetch = require('whatwg-fetch') }
const authApi = {
register (userData) {
fetch(`http://localhost/api/auth/local/register`, {
method : 'POST',
headers : {
'Accept' : 'application/json',
'Content-Type' : 'application/json'
},
body : JSON.stringify({
name : userData.name,
email : userData.email,
password : userData.password
})
})
.then(statusHelper)
.then(response => response.json())
.catch(error => error)
.then(data => data)
}
}
function statusHelper (response) {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response)
} else {
return Promise.reject(new Error(response.statusText))
}
}
export default authApi
The API request does return a valid object however the return from the Saga call always is undefined. Can anyone guide me to where I am wrong?
Thanks in advance!
Best Regards,
Bruno
You forgot to return the promises from your function. Make it
const authApi = {
register (userData) {
return fetch(`http://localhost/api/auth/local/register`, {
// ^^^^^^
method : 'POST',
headers : {
'Accept' : 'application/json',
'Content-Type' : 'application/json'
},
body : JSON.stringify({
name : userData.name,
email : userData.email,
password : userData.password
})
})
.then(statusHelper)
.then(response => response.json());
}
};

Categories