In my util.ts I am importing and using lambda-log:
util.ts
import * as logger from 'lambda-log';
export async function prepareMessage(req){
try {
logger.options.meta.clientId = req.clientId;
if (!req.templateId) {
throw new Error(`template is missing`);
}
} catch(error){
logger.error('error occured', error);
}
}
I want to test in my util.test.ts that logger.error contains clientId I set in options.meta.clientId.
This is what I got so far, but it is not working:
util.test.ts
import * as logger from 'lambda-log';
jest.mock('lambda-log', () => ({
...jest.requireActual('lambda-log'),
error: jest.fn()
}));
it('sets clientId in logger.options.meta from request payload', async () => {
const record = { clientId: 'client-test' };
const optionsSpy = jest.spyOn(logger, 'error');
try {
await prepareMessage(record);
} catch (err) {
expect(optionsSpy).toHaveBeenCalled();
expect(optionsSpy).toHaveBeenCalledWith(
expect.objectContaining({
clientId: 'client-test'
})
);
}
}
Does anyone know how to spy lambda-log and how to accomplish this?
Related
I'm trying to call my global variables in my controller but i got an error variable is not defined. Please see the code below for your reference. Hoping to solve my problem. Thank you Guys
**server.js **
const serverConfig = require('./config/server.config')
const app = require('fastify')({ logger: true })
require('./models/response.model')
const mongoose = require('mongoose')
const conn = require('./config/monggo.config')
require('./routes/dbm.routes')(app)
const connect = async () => {
try {
await mongoose.connect(conn.uri)
console.log('Connected to Mongoose!')
} catch (error) {
console.log(error)
}
}
connect();
app.listen(serverConfig.port, '::', (err, address) => {
if (err) {
app.log.error(err)
process.exit(1)
}
console.log('Listening at', address)
})
response.model.js
module.exports = function () {
global.successModel = {
status: 'sucess',
statusCode: 0,
isSuccess: true,
message: ''
}
global.failModel = {
status: 'failed',
statusCode: 1,
isSuccess: false,
message: 'Error encountered while processing request.'
}
}
**monggo.controller.js
**
exports.getProducts = async (req, res) => {
//find Products in the databse
Product.find({}, (err, product) => {
//send error message if not found
if (err) {
res.send(err);
}
//else pass the Products
res.send(successModel);
})
await res;
}
Hoping to solve my problem. Thank you
The './models/response.model' file exports a function that you need to call to "install" your globals.
- require('./models/response.model')
+ require('./models/response.model')()
As a suggestion, you should avoid to use globals, in fastify you can use:
decorator to add to your app instance useful data such as configs
Moreover, your mongoose connection is unrelated with Fastify, you can encapsulate it into a plugin to be sure that fastify is starting after connecting to the database:
const fp = require('fastify-plugin')
app.register(fp(async function connect (instance, opts) {
await mongoose.connect(conn.uri)
}))
So whenever the app is loaded it should check for user Auth using the loadUser(), the problem I'm having is that if there is no token in localStorage, the server won't return any errors(when its suppose to). I looked at the code for auth(backend), and it returns a status meassage when no token received, I was wondering is it because no token isn't a type of error, that's way the server didn't send an error response?
Below are the code snippets:
auth.js(backend)
const jwt = require("jsonwebtoken");
const config = require("config");
module.exports = function (req, res, next) {
//get token from header
const token = req.header("x-auth-token");
// check if not token
if (!token) {
return res.status(401).json({ msg: "no token, auth denied" });
}
//verify token
try {
const decoded = jwt.verify(token, config.get("jwtSecret"));
req.user = decoded.user;
next();
} catch (err) {
res.status(401).json({
msg: "token isnt valid",
});
}
};
App.js
const App = () => {
useEffect(() => {
if (localStorage.token) {
setAuthToken(localStorage.token);
store.dispatch(loadUser());
}
}, []);
auth.js Redux
export const loadUser = () => async (dispatch) => {
console.log("from auth.js");
if (localStorage.token) {
setAuthToken(localStorage.token);
}
try {
const res = await axios.get("/api/auth");
console.log("inside auth.js get auth route");
dispatch({
type: USER_LOADED,
payload: res.data,
});
} catch (err) {
console.log("error from auth.js");
dispatch({
type: AUTH_ERROR,
});
}
};
Basically the code inside catch(err) { //code }
is not executed.
Silly of me, added else condition into App.js solved the issue.
I wanted to get user information from my collection using their ID to send them notifications. This are my functions in index.ts
export const sendNotifications = functions.firestore
.document('messages/{groupId1}/{groupId2}/{message}')
.onCreate((snapshot, context) =>{
console.log('Starting sendNotification Function');
const doc = snapshot.data();
console.log(doc.content);
console.log(getUserData(doc.idFrom))
return true;
});
export async function getUserData(id: string){
try {
const snapshot = await admin.firestore().collection('users').doc(id).get();
const userData = snapshot.data();
if(userData){
return userData.nickname;
}
} catch (error) {
console.log('Error getting User Information:', error);
return `NOT FOUND: ${error}`
}
}
From my deploy, I get the console log messages, the 'Starting sendNotification Function', then the actual 'doc.content' then an error for my 'getUserData(doc.idFrom)'.
Promise {
<pending>,
domain:
Domain {
domain: null,
_events: { error: [Function] },
_eventsCount: 1,
_maxListeners: undefined,
members: [] } }
Thank you in advance!
You should call your async getUserData() function with await.
The following should do the trick (untested):
export const sendNotifications = functions.firestore
.document('messages/{groupId1}/{groupId2}/{message}')
.onCreate(async (snapshot, context) => {
try {
console.log('Starting sendNotification Function');
const doc = snapshot.data();
console.log(doc.content);
const nickname = await getUserData(doc.idFrom);
// Do something with the nickname value
return true;
} catch (error) {
// ...
}
});
async function getUserData(id: string) {
try {
const snapshot = await admin.firestore().collection('users').doc(id).get();
if (snapshot.exists) {
const userData = snapshot.data();
return userData.nickname;
} else {
//Throw an error
}
} catch (error) {
// I would suggest you throw an error
console.log('Error getting User Information:', error);
return `NOT FOUND: ${error}`;
}
}
Or, if you don't want to have the Cloud Function async, you can do as follows:
export const sendNotifications = functions.firestore
.document('messages/{groupId1}/{groupId2}/{message}')
.onCreate((snapshot, context) => {
console.log('Starting sendNotification Function');
const doc = snapshot.data();
console.log(doc.content);
return getUserData(doc.idFrom)
.then((nickname) => {
// Do something with the nickname value
return true;
})
.catch((error) => {
console.log(error);
return true;
});
});
I have this test:
describe('createNote', () => {
beforeEach(() => {
res = {
json: sinon.spy(),
sendStatus: sinon.spy(),
};
});
afterEach(() => {
noteService.createUserNote.restore();
});
it('should return user note object', async () => {
// Arrange
modelResponse = {
id: 1,
userId: req.user.id,
...req.body,
};
sinon.stub(noteService, 'createUserNote')
.resolves(modelResponse);
// Act
await userController.createNote(req, res);
// Assert
sinon.assert.calledWith(
noteService.createUserNote,
req.user,
req.body.note,
);
sinon.assert.calledWith(res.json, { note: modelResponse });
});
It fails on line sinon.assert.calledWith(res.json, { note: modelResponse });
I don't really understand sinon so I'm not sure why though.
This is my userController code:
createNote: async (req, res, next) => {
try {
const createNote = await noteService.createUserNote(
req.user,
req.body.note,
);
const note = await noteService.getUserNote(
req.user.id,
createNote.id,
);
return res.json({ note });
} catch (err) {
return next(err);
}
},
I recently changed it from this so assume something in what I've done has caused the test to fail:
createNote: async (req, res, next) => {
try {
const note = await noteService.createUserNote(
req.user,
req.body.note,
);
return res.json({ note });
} catch (err) {
return next(err);
}
},
This is the error I get:
1) User userController
createNote
should return user note object:
AssertError: async (user, text) => {
const [note] = await db.Note.createUserNote(user.id, text, db);
await emailService.userAlert(text, user.name);
return note;
} is not stubbed
at Object.fail (node_modules/sinon/lib/sinon/assert.js:106:21)
at /opt/atlassian/pipelines/agent/build/node_modules/sinon/lib/sinon/assert.js:35:24
at Array.forEach (<anonymous>)
at verifyIsStub (node_modules/sinon/lib/sinon/assert.js:22:5)
at Object.assert.(anonymous function) [as calledWith] (node_modules/sinon/lib/sinon/assert.js:77:9)
at Context.it (app/__tests__/controllers/user/userController.test.js:56:20)
at <anonymous>
Can anybody explain what is wrong and how to fix this?
You need to mock getUserNote as well. After the change, you are getting note from getUserNote and then sending it to res.json
But in the test case you have not stubbed it. Try adding this in the test case:
sinon.stub(noteService, 'getUserNote')
.resolves(modelResponse);
I'm currently learning how to use Knex and I'm having trouble having the functions I've written run in the correct order.
When the code is run, what I'm expecting to happen is the tables are dropped (if they exist), the tables are created, and finally the tables are seeded with data. Right now the seeding function is running before the table creation which causes the program to crash.
It should run in the following order in index.js: main() > dropTables() > createTables() > seedTables().
How do I get these functions to run in the correct order?
index.js
require("babel-core/register")
require("babel-polyfill")
import { makeUserTable, dropUserTable } from './models/users'
import { makeGameTable, dropGameTable } from './models/games'
import { seedUser } from './seeds/users'
import { seedGame } from './seeds/games'
const dbConnection = require('knex')({
client: 'mysql',
debug: false,
connection: {
host: 'localhost',
user: 'samurai',
password: 'bushido',
database: 'knex_sandbox'
}
})
function dropTables() {
dropUserTable(dbConnection)
dropGameTable(dbConnection)
}
function makeTables() {
makeUserTable(dbConnection)
makeGameTable(dbConnection)
}
function seedTables() {
// seedUser(dbConnection)
// seedGame(dbConnection)
console.log('seed tables ran')
}
const main = () => {
try {
dropTables()
makeTables()
seedTables()
// kill program
dbConnection.destroy()
console.log('===> Script done. Exiting.')
} catch (err) {
console.log('===> Something went wrong:\n', err)
}
}
export default main(dbConnection)
models/users.js
export const makeUserTable = (dbConnection) => {
dbConnection.schema
.createTableIfNotExists('users', function (table) {
table.increments('user_id').primary()
table.string('username', 100)
table.text('bio', 100)
})
.then(() => {
console.log('===> User table created.')
})
.catch(err => {
console.log('===> Something went wrong creating the user table:\n', err)
})
}
export const dropUserTable = (dbConnection) => {
dbConnection.schema
.dropTableIfExists('users')
.then(() => {
console.log('===> User table dropped (if it exists).')
})
.catch(err => {
console.log('===> Something went wrong dropping the user table:\n', err)
})
}
models/games.js
export const makeGameTable = (dbConnection) => {
dbConnection.schema
.createTableIfNotExists('games', function (table) {
table.increments('game_id')
.primary()
table.string('title', 100)
table.text('description', 100)
// table.integer('user_id')
// .unsigned()
// .references('users.user_id')
// .onDelete('cascade')
})
.then(() => {
console.log('===> Game table created.')
})
.catch(err => {
console.log('===> Something went wrong creating the game table:\n', err)
})
}
export const dropGameTable = (dbConnection) => {
dbConnection.schema
.dropTableIfExists('games')
.then(() => {
console.log('===> Game table dropped (if it exists).')
})
.catch(err => {
console.log('===> Something went wrong dropping the game table:\n', err)
})
}
seeds/users.js
export const seedUser = (dbConnection) => {
dbConnection
.insert({
username: 'dog',
bio: 'Hello, this is dog'
})
.into('users')
.then(() => {
console.log('===> User seeded')
})
.catch(err => {
console.log('===> Something went wrong seeding the user table:\n', err)
})
}
seeds/games.js
export const seedGame = (dbConnection) => {
dbConnection
.insert({
title: 'Bone',
description: 'Om nom nom',
// user_id: 1
})
.into('games')
.then(() => {
console.log('===> Game seeded')
})
.catch(err => {
console.log('===> Something went wrong seeding the game table:\n', err)
})
}
Instead of just calling dbConnection... in your arrow functions you should also return the created promise lie this return dbConnection... and put awaits back before calling them.
require("babel-core/register")
require("babel-polyfill")
import { makeUserTable, dropUserTable } from './models/users'
import { makeGameTable, dropGameTable } from './models/games'
import { seedUser } from './seeds/users'
import { seedGame } from './seeds/games'
const dbConnection = require('knex')({
client: 'mysql',
debug: false,
connection: {
host: 'localhost',
user: 'samurai',
password: 'bushido',
database: 'knex_sandbox'
}
})
async function dropTables() {
await dropUserTable(dbConnection)
await dropGameTable(dbConnection)
}
async function makeTables() {
await makeUserTable(dbConnection)
await makeGameTable(dbConnection)
}
async function seedTables() {
// seedUser(dbConnection)
// seedGame(dbConnection)
console.log('seed tables ran')
}
const main = async () => {
try {
await dropTables()
await makeTables()
await seedTables()
// kill program
await dbConnection.destroy()
console.log('===> Script done. Exiting.')
} catch (err) {
console.log('===> Something went wrong:\n', err)
}
}