const mongoose=require('mongoose');
const assert = require('assert')
describe('Finding records', function () {
var char;
beforeEach(function (done) {
char = new MarioChar({
name: 'Mario'
});
char.save().then(function () {
assert(char.isNew === false);
done();
});
});
it('Finds one record from the database', function (done) {
findOne({ name: 'Mario' }).then(function (result) {
assert(result.name === 'Mario');
done();
});
});
it('Finds one record from the database', function (done) {
findOne({ _id: char._id }).then(function (result) {
assert(result._id === char._id);
done();
});
});
});
The code is to find the records from MongoDB and
I have tried to pass these test case but these test case are failing therefore can someone please tell me where I am making mistake
Related
I am working on creating unit tests for a project that uses Typeorm without Nestjs. The file I am creating unit tests for uses queryRunner to start a transaction. My problem is, I am not able to mock the Datasource. I tried multiple ways but the mock is never getting called to replace the actual Datasource that has access to the postgresql database. I saw some solutions to mock it, but they all use Nestjs, which I don't use in my case.
The error I am having in the tests right now is:
Received promise rejected instead of resolved
Rejected to value: [TypeORMError: Driver not Connected]
Any help would be highly appreciated since I'm not an expert in unit tests.
Here's an example of the code that I am having the issue with (replaced some names tho):
datasource.ts
//database config is defined in this file
export const datasource: DataSource = new DataSource(some_config);
dummy.service.ts
export const dummyService = () => {
//datasource is imported from the above file
const queryRunner = datasource.createQueryRunner();
await queryRunner.startTransaction();
try {
const foundObject = await queryRunner.manager.getRepository(MyObject).findOne({
where: { id: someId },
lock: { mode: 'pessimistic_write' },
});
//some more database calls
} catch (error) {
await queryRunner.rollbackTransaction();
} finally {
await queryRunner.release();
}
}
mock.datasource.ts
import { DataSource } from 'typeorm';
export const dataSourceMockFactory: () => MockType<DataSource> = jest.fn(
() => ({
createQueryRunner: jest.fn().mockImplementation(() => ({
connect: jest.fn(),
startTransaction: jest.fn(),
release: jest.fn(),
rollbackTransaction: jest.fn(),
manager: {
getRepository: jest.fn().mockImplementation(() => ({
create: jest.fn(),
findOne: jest.fn(() => {
return getMyDummyObject();
}),
})),
save: jest.fn(),
},
})),
}),
);
export type MockType<T> = {
// eslint-disable-next-line #typescript-eslint/ban-types
[P in keyof T]?: jest.Mock<{}>;
};
dummy.unit.test.ts
describe('dummy service test', () => {
let dataSourceMock: MockType<Typeorm.DataSource>;
beforeEach(async () => {
// This method did not work
jest.mock('typeorm', () => {
const actual = jest.requireActual('typeorm');
return {
...actual,
DataSource: dataSourceMockFactory(),
};
});
// The below method did not work either
jest.mock('./../../db/datasource', () => ({
datasource: dataSourceMockFactory(),
}));
});
afterEach(() => {
jest.clearAllMocks();
});
it('should test dummy service with transaction', async () => {
// getting an error here
await expect(
dummyFunction(),
).resolves.not.toThrow();
});
});
I'm trying to setup testing my node with mongo app using Jest. I've set it up and copied their sample verbatim, which works fine, except when I call the db.close(); function. It gives me a TypeError: that db.close is not a function. This is directly out of their example:
import { MongoClient } from 'mongodb';
describe('insert', () => {
let connection;
let db;
beforeAll(async () => {
connection = await MongoClient.connect(global.__MONGO_URI__, {
useNewUrlParser: true,
});
db = await connection.db(global.__MONGO_DB_NAME__);
});
afterAll(async () => {
await connection.close();
await db.close();
});
it('should insert a doc into collection', async () => {
const users = db.collection('users');
const mockUser = {_id: 'some-user-id', name: 'John'};
await users.insertOne(mockUser);
const insertedUser = await users.findOne({_id: 'some-user-id'});
expect(insertedUser).toEqual(mockUser);
});
});
I have a setup file for my tests that looks like this:
const mongoose = require('mongoose');
mongoose.set('useCreateIndex', true);
mongoose.promise = global.Promise;
async function removeAllCollections() {
const collections = Object.keys(mongoose.connection.collections);
for (const collectionName of collections) {
const collection = mongoose.connection.collections[collectionName];
await collection.deleteMany();
}
}
async function dropAllCollections() {
const collections = Object.keys(mongoose.connection.collections);
for (const collectionName of collections) {
const collection = mongoose.connection.collections[collectionName];
try {
await collection.drop();
} catch (error) {
// Sometimes this error happens, but you can safely ignore it
if (error.message === 'ns not found') return;
// This error occurs when you use it.todo. You can
// safely ignore this error too
if (error.message.includes('a background operation is currently running'))
return;
console.log(error.message);
}
}
}
export default function setupDB(databaseName) {
// Connect to Mongoose
beforeAll(async () => {
const url = `mongodb://127.0.0.1/${databaseName}`;
await mongoose.connect(
url,
{
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true
},
err => {
if (err) {
console.error(err);
process.exit(1);
}
}
);
});
// Cleans up database between each test
afterEach(async () => {
await removeAllCollections();
});
// Disconnect Mongoose
afterAll(async () => {
await dropAllCollections();
await mongoose.connection.close();
});
}
I am then writing tests like this:
import User from 'db/models/User';
import setupDB from 'utils/setupDbForTesting';
setupDB('mongoose_bcrypt_test');
it('correctly hashes and salts passwords', async done => {
// create a user a new user
const newUser = new User({
username: 'jmar777',
password: 'Password123'
});
await newUser.save(function (err) {
if (err) {
console.log(err);
}
});
const user = await User.findOne({ username: 'jmar777' });
user.comparePassword('Password123', function (err, isMatch) {
if (err) throw err;
expect(isMatch).toBeTruthy();
});
user.comparePassword('123Password', function (err, isMatch) {
if (err) throw err;
expect(isMatch).toBeFalsy();
});
done();
});
However, every other time I run these tests, they pass (or fail) so for every time T that the tests pass, T + 1 they will fail. My question is - why?
The tests fail because user (in the callback for User.findOne) returns null, even though the user has been saved.
I think the issue lies in the tearing down of the database, but I really can't see any problems. Any help would be appreciated, thanks.
I am passing a parameter to the axios get request. It works on postman properly but does not work with my code. I don't know where I am making a mistake.
I want only one specific data from db but I am receiving all the data in available in the collection. But with postman I get the desired data
backend route :
router.get('/displayUser', (req,res) => {
const query = user = req.body ;
Services.find(query)
.exec((err, services) => res.json(services))
})
axios call : I tried two different ways and both didn't work
method 1:
getData: async function () {
const user = this.userId
console.log(user)
let res = await axios.get('http://localhost:5000/api/services/displayUser' , { params: { user }})
console.log(res.data);
}
method 2:
getData: async function () {
var data = JSON.stringify({"user":this.userId});
console.log(data)
var config = {
method: 'get',
url: 'http://localhost:5000/api/services/displayUser',
headers: {
'Content-Type': 'application/json'
},
data : data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
}
When I get the data in console I am getting all 3 objects available in collection instead of the specific one related to the user Id
Screenshot
But in postman It works as desired
screenshot
I do this as following:
when I need a get :
app.get('/detail/:id', function (req, res) {
//console.log(req.params.id);
var url=urlDetail + "/" + req.params.id;
axios.get(url)
.then(function (response) {
// result=response.data;
res.render('database', { title: 'Detail' , dbs: response.data ,Version:pjson.version});
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
//console.log("ici always");
});
});
and when i need to post (req.body is a json):
app.post('/carto/demande', function (req, res) {
let data;
console.log(req.params);
console.log(req.body);
var url=urlCartoDemande;
axios.post(url,req.body)
.then(function (response) {
data=response.data;
res.render('carto', { title : 'Demande' ,Version:pjson.version,mode:"resultat",data:data } );
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});
});
I'm using the best practice MongoDB with Lambda example from here https://docs.atlas.mongodb.com/best-practices-connecting-to-aws-lambda/
I need to publish to SNS but are unable to due to the callbackWaitsForEmptyEventLoop = false, if I uncomment this, it works fine but then my Lambda function just times out and never receive the success callback.
"use strict";
const MongoClient = require('mongodb').MongoClient;
const MONGODB_URI = process.env.MONGODB_URI; // or Atlas connection string
const AWS = require('aws-sdk');
const SNS_TOPICARN = process.env.SNS_TOPICARN;
const sns = new AWS.SNS({ apiVersion: '2010-03-31' });
let cachedDb = null;
function connectToDatabase(uri) {
console.log('=> connect to database');
if (cachedDb) {
console.log('=> using cached database instance');
return Promise.resolve(cachedDb);
}
return MongoClient.connect(uri)
.then(db => {
cachedDb = db;
return cachedDb;
});
}
function queryDatabase(db) {
console.log('=> query database');
return db.collection('items').find({}).toArray()
.then((data) => { return { statusCode: 200, data: data }; })
.catch(err => {
console.log('=> an error occurred: ', err);
return { statusCode: 500, data: null };
});
}
exports.handler = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
console.log('event: ', event);
connectToDatabase(MONGODB_URI)
.then(db => queryDatabase(db))
.then(result => {
console.log('=> returning result: ', result);
var params = {
Message: result.data,
Subject: 'Devices Lost Connection',
TopicArn: SNS_TOPICARN
};
sns.publish(params, function (err, data) {
if (err) console.log(err, err.stack);
else console.log(data);
});
callback(null, result);
})
.catch(err => {
console.log('=> an error occurred: ', err);
callback(err);
});
};
Problem solved, will leave it here if someone else has the same issue:
I need to do the handler callback in the callback of the second function:
sns.publish(params, function (err, data) {
if (err) console.log(err, err.stack);
else console.log(data);
callback(null, result);
});