I am running unit test for API call that is serving post request. I am passing request body and must get back response as account data. But I am getting only assertion error
Note: The data is fetched from Azure
spec.js
const accounts=require('./accounts');
const should=require('chai').should();
const chai=require('chai');
const chaiAsPromised=require('chai-as-promised');
chai.use(chaiAsPromised);
chai.should();
....
beforeEach(function()
{
mockResponse=
[
{
"AccountId": "xyz",
"AccountState": "Active"
}
]
it('Should get account from Azure API', function() {
return accounts.getActivatedAccounts(req.body.customerNumber).
should.eventually.equal(mockResponse);
});
**JavascriptFile**
function getActivatedAccounts(accounts) {
let promise = new Promise(function(resolve, reject) {
fetch(Url , { headers: config.headersAPIM})
.then(response => response.json())
.then(accounts => {
if (accounts) {
Accounts[accounts] = [];
for (account in accounts) {
let accountType = accounts[account]['type]'];
Accounts[email].push(accounts[account]);
}
let reply = {
status : "SUCCESS",
data : Accounts[accounts]
}
resolve(reply);
} else {
let reply = {
status : "SUCCESS",
data : accounts
}
resolve(reply);
}
})
.catch(err => {
console.log("Error: Could not find accounts");
console.log('Error:' + err);
let reply = {
status:"FAILURE",
err: "Error: Could not find accounts. " + err
}
resolve(reply);
})
});
return promise;
}
I am not able to give javascript file that is calling the service, I will give it in the answer section
Sounds like you're asking about the Chai assertion.
equal uses strict equality so unless the two objects are literally the same object it will fail.
eql uses a deep equality comparison and will pass if the objects have the same properties and values.
Here is a simple example:
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
chai.should();
const getActivatedAccounts = () =>
Promise.resolve({ status: 'SUCCESS', data: ['some', 'data'] });
it('Should get account from Azure API', function () {
return getActivatedAccounts()
.should.eventually.eql({ status: 'SUCCESS', data: ['some', 'data'] }); // Success!
});
Related
This code is being used in a Sveltekit web application.
In the first step I get a user jwt token from an api like : dashboard.example.com/auth/local
and in the second step I'm using the response of the first api call to get full information from an api endpoint like this : example.com/api/users/token
This is an endpoint in an Sveltekit application:
import { json as json$1, error } from '#sveltejs/kit';
import axios from 'axios';
import md5 from 'md5';
import { SITE_ADDRESS } from '$lib/Env';
let userToken;
/** #type {import('#sveltejs/kit').RequestHandler} */
export async function POST({ request }) {
const bodyData = await request.json();
let identifier = bodyData.data.identifier;
let password = bodyData.data.password;
let loginToken = bodyData.data.loginToken;
let newLoginToken = md5(identifier + password + process.env.SECURE_HASH_TOKEN);
let dataResult = await axios
.post(`${import.meta.env.VITE_SITE_API}/auth/local`, {
identifier: identifier,
password: password
})
.then((response) => {
return response.data;
})
.then((response) => {
let userSummaryData = response;
userToken = md5(
userSummaryData.user.username + userSummaryData.user.id + process.env.SECURE_HASH_TOKEN
);
let userCompleteData = axios
.post(`${SITE_ADDRESS}/api/users/${userToken}`, {
data: {
userID: userSummaryData.user.id,
username: userSummaryData.user.username
}
})
.then((response) => {
return {
userJWT: userSummaryData.jwt,
userSummary: userSummaryData.user,
userFullSummary: response.data.userFullSummary
};
});
return userCompleteData;
})
.catch((error) => {
// console.log(' ---- Err ----');
});
if (dataResult && newLoginToken == loginToken) {
return json$1(
{
userJWT: dataResult.userJWT,
userSummary: dataResult.userSummary,
userFullSummary: dataResult.userFullSummary
},
{
headers: {
'cache-control': 'private, max-age=0, no-store'
}
}
);
} else if (dataResult && newLoginToken != loginToken) {
throw error(400, 'Something wrong happened');
}
throw error(401, 'Something wrong happened');
}
This code is work perfectly in localhost. But when I test it on host I get error 401.
and the question is :
Why this works on localhost but doesn't work on the server?
How can I improve this kind of promises (I'd like to use the response of the first api call in the second api call and return both
as a result)
I have a fetch request to delete some lists from my backend, but the console is giving me a complaint. The console says "Uncaught (in promise)."
This is my fetch() in the frontend:
const handleClickGarbage = (key) => { // for deleting a grocery list
const temp = loginUserr;
try {
console.log('inside click garbage');
const accessToken = temp.accessToken;
console.log(accessToken);
const param = key;
console.log(param);
fetch(`http://localhost:3010/v0/grocerylists?listName=${param}`, {
method: 'DELETE',
headers: new Headers({
'Authorization': 'Bearer ' + accessToken,
}),
})
.then((results) => {
if (!results.ok) {
throw results;
}
console.log(results);
getCurrentGroceryListTabInfo(); // get the current tab info again because we just updated the info
});
} catch (e) {
console.log(e);
}
};
This is my user.js:
exports.deleteGroceryList = async (req, res) => {
const listNamee = req.query.listName;
const memberIdd = req.userID;
console.log('inside delete gl');
console.log(listNamee);
console.log(memberIdd);
const deleted = await db.deleteGroceryList(listNamee, memberIdd);
console.log('user.js line 286)\n');
console.log(deleted);
if (deleted === null) {
res.status(400).send();
} else {
console.log('user.js line 292)\n');
res.sendStatus(200);
}
};
This is my db.js:
exports.deleteGroceryList = async (listNamee, memberIdd) => {
const listName = listNamee;
const memberId = memberIdd;
const select = 'DELETE FROM grocery_list WHERE list_name = $1 AND member_id = $2 RETURNING *';
const query = {
text: select,
values: [listName, memberId],
};
const {rows} = await pool.query(query);
console.log('db.js line 495)\n');
console.log(rows);
if (rows.length > 0) {
return rows.length;
} else {
return null;
}
};
And this is my openapi.yaml:
/grocerylists:
delete:
description: Deletes a grocery list from user's existing grocery lists'
security:
- bearerAuth: []
parameters:
- name: listName
in: query
description: name of grocery list to delete
schema:
type: string
responses:
200:
description: Removed list from grocery lists successfully
401:
description: Unauthorised
400:
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
I suspect it is something wrong with my api because console.logging results in the front end shows that user.js returned a status code of 200.:
But then the console also says uncaught promise:
You used .then() syntax to handle Promise. When you choose to use .then() syntax, you should catch the error with .catch(), and you don't have that in your code. Just add catch() method to a Promise that fetch returns.
fetch(`http://localhost:3010/v0/grocerylists?listName=${param}`, {
method: 'DELETE',
headers: new Headers({
'Authorization': 'Bearer ' + accessToken,
),
})
.then((results) => {
if (!results.ok) {
throw results;
}
console.log(results);
getCurrentGroceryListTabInfo(); // get the current tab info again because we just updated the info
})
.catch((error) => {
console.log('ERROR: ', error)
});
I am new to Node.js and I am struggling with Promises even after reading the tutorials provided by other stackflow users. I have already spent a whole evening on this and I am looking for help. I get the following error " Function returned undefined, expected Promise or value". My code is below. What am I doing wrong? I also have a suspicion that I have to use await/async because it looks like my code is running through without waiting for the first get to complete.
const admin = require('firebase-admin');
const functions = require('firebase-functions');
var db = admin.firestore();
exports.declinedRequest = functions.firestore
.document('requests/{requestId}')
.onUpdate((change, context) => {
const newValue = change.after.data();
const status = newValue.status;
const request = context.params.requestId;
var registrationToken;
var message;
if(status=="created") {
console.log('Checkpoint1 ',context.params.requestId);
newValue.friends.forEach(doc => {
console.log('Checkpoint 2: ', doc);
var usersRef = db.collection('users');
var query = usersRef.where('mobile', '==', doc).get()
.then(snapshotFriend => {
if (snapshotFriend.empty) {
console.log('Checkpoint3.');
return;
}
snapshotFriend.forEach(mobile => {
registrationToken = mobile.data().fcmToken;
console.log('FCM token =>', registrationToken);
if (!registrationToken) {
console.log('No fcmToken available');
return;
}
message = {
notification: {
body: "Request still available from " + newValue.requesterName,
sound: "default",
badge: 1
},
data: {
requestId: `${request}`
}
};
console.log('FCM token message created');
})
})
})
} else {
return;
}
return admin.messaging().sendToDevice(registrationToken, message)
.then(function (response) {
console.log("Successfully sent message:", response)
})
.catch(function (error) {
console.log("Error sending message:", error);
})
})
Try the code below hope this will work.
const admin = require('firebase-admin');
const functions = require('firebase-functions');
const Promise = require('bluebird');
const _ = require('lodash');
let db = admin.firestore();
exports.declinedRequest = functions.firestore
.document('requests/{requestId}')
.onUpdate((change, context) => {
const newValue = change.after.data();
const status = newValue.status;
const request = context.params.requestId;
if (status == "created") {
console.log('Checkpoint1 ', context.params.requestId);
allPromises = [];
newValue.friends.forEach(doc => {
console.log('Checkpoint 2: ', doc);
const usersRef = db.collection('users');
// query for each document return promise.
allPromises.push(queryForEachDocument(doc,request,usersRef));
});
return Promise.all(allPromises);
} else {
return Promise.reject / resolve('Whatever you want.');
}
})
function queryForEachDocument(doc,request,usersRef) {
let promiseInvoices = []
let registrationToken;
let message;
return usersRef.where('mobile', '==', doc).get().then((snapshotFriend) => {
if (_.isEmpty(snapshotFriend)) {
console.log('Checkpoint3.');
return Promise.reject(new Error('Your error'));
}
snapshotFriend.forEach(mobile => {
registrationToken = mobile.data().fcmToken;
console.log('FCM token =>', registrationToken);
if (!registrationToken) {
console.log('No fcmToken available for', newValue.requesterName);
// Do anything you want to change here.
return Promise.reject(new Error('No fcmToken available for',newValue.requesterName));
}
message = {
notification: {
body: "Request still available from " + newValue.requesterName,
sound: "default",
badge: 1
},
data: {
requestId: request
}
};
console.log('FCM token message created');
// send invoice for each registrationToken
promiseInvoices.push(sendInvoice(registrationToken, message))
});
}).then(() => {
return Promise.all(promiseInvoices);
})
}
function sendInvoice(registrationToken, message) {
return admin.messaging().sendToDevice(registrationToken, message)
.then(function (response) {
console.log("Successfully sent message:", response)
})
.catch(function (error) {
console.log("Error sending message:", error);
})
}
I have to send a message to many token when a node is created in my realtime database.
I use that's code, but any notification are lost (people not receive its).
exports.sendMessage = functions.database.ref('/messages/{messageId}')
.onCreate((snapshot, context) => {
const original = snapshot.val();
let msg = {
message: {
data: {
title: 'title2 test',
body: 'body2 test',
notify_type: 'chat_message',
notify_id: ((new Date()).getTime()).toString(),
},
apns: {
headers: {
'apns-priority': '10',
'apns-expiration': '0'
},
payload: {
aps: { contentAvailable: true, sound:'' },
'acme1': 'bar',
title: 'title test',
body: 'body test',
notify_type: 'chat_message',
notify_id: ((new Date()).getTime()).toString()
}
},
token: token
}
};
var query = firebase.database().ref("users");
return query.once("value")
.then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var user = childSnapshot.val();
var token = user.token;
var username = user.username;
msg.message.token = token;
admin.messaging().send(msg.message).then((response) => {
console.log('message sent to '+username);
}).catch((error) => {
console.log(error);
});
});
});
});
Is the "return" Promise right ? I think I have to wait all "admin.messagging() Promise, but I don't know how can I do this.
Thank you so much.
This is how you send a FCM to an array of tokens:
return Promise.all([admin.database().ref(`/users/${user}/account/tokensArray`).once('value')]).then(results => {
const tokens = results[0];
if (!tokens.hasChildren()) return null;
let payload = {
notification: {
title: 'title',
body: 'message',
icon: 'icon-192x192.png'
}
};
const tokensList = Object.keys(tokens.val());
return admin.messaging().sendToDevice(tokensList, payload);
});
You can send notifications to an array of tokens. I am using this code to send notifications
return admin.messaging().sendToDevice(deviceTokenArray, payload, options).then(response => {
console.log("Message successfully sent : " + response.successCount)
console.log("Message unsuccessfully sent : " + response.failureCount)
});
I think you can find more information here
https://firebase.google.com/docs/cloud-messaging/admin/legacy-fcm
To return a Promise for all the send actions, modify your code to this:
return query.once("value")
.then(function(snapshot) {
var allPromises = [];
snapshot.forEach(function(childSnapshot) {
var user = childSnapshot.val();
var token = user.token;
var username = user.username;
msg.message.token = token;
const promise = admin.messaging().send(msg.message).then((response) => {
console.log('message sent to '+username);
}).catch((error) => {
console.log(error);
});
allPromises.push(promise);
});
return Promise.all(allPromises);
});
I am currently experimenting Google Firebase functions to access Google APIs. It's running fine, but I am a little bit lost in trying to manage the errors that could be detected ...
In the .HTTPS getGoogleUsers functions , I would like to return an HTTP status code ( 200 or error code ) , and the data ( or error message )
As far as I can see , I can get errors:
from the connect() function ( 500: Internal server error or 401 Unauthorized )
from the listUsers() function ( 500: Internal server error or 400 Bad Request )
Am I totally or partially wrong ? what should be my strategy in this case ?
thanks for feedback ..
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const {google} = require('googleapis');
const KEY = require('./service-key.json');
// Create JSON Web Token Client
function connect () {
return new Promise((resolve, reject) => {
const jwtClient = new google.auth.JWT(
KEY.client_email,
null,
KEY.private_key,
['https://www.googleapis.com/auth/admin.directory.user'],
'adminuser#mydomain.com'
);
jwtClient.authorize((err) => {
if(err) {
reject(err);
} else {
resolve(jwtClient);
}
});
});
}
function listUsers (client) {
return new Promise((resolve, reject) => {
google.admin('directory_v1').users.list({
auth: client,
domain: 'mydomain.com',
}, (err, response) => {
if (err) {
reject(err);
}
resolve(response.data.users);
});
});
}
function getAllUsers () {
connect()
.then(client => {
return listUsers(client);
})
.catch(error => {
return error;
})
}
exports.getGoogleUsers = functions.https.onRequest((req, res) => {
const users = getAllUsers();
if (error) {
status = error.status;
data = error.message;
} else {
status = 200;
data = users;
}
res.send({ status: status, datas: data })
});
I think you are looking for
function getAllUsers () {
return connect().then(listUsers);
//^^^^^^
}
exports.getGoogleUsers = functions.https.onRequest((req, res) => {
getAllUsers().then(users => {
return {status: 200, datas: users};
}, error => {
return {status: error.status, datas: error.message};
}).then(response => {
res.send(response);
});
});
This uses the .then(…, …) method with two callbacks to distinguish between success and error case, and to wait for the result of the promise.