i'm trying to test all the way of my api with mocha but when i trying to export the userId (user i'm created in post) to try to get he in get(another folder) my user_id come undefined
Here an example:
var userId
describe('POST TESTS', () => {
it("POST User", (done) => {
var user = {
name: "Pedro",
email: "xxxx#gamer.com"
}
chai.request(server)
.post('/register/user')
.send(user)
.end((err, res) => {
res.should.have.status(200)
res.body.id.should.be.a("number")
userId = res.body.id
done()
})
})})
module.exports = userId
And when i try to log this in another file or even before module.exports, userId is undefined
Explained in this question
The variable will not be updated, so the second test will get the initial value. Which in this case is undefined because is not initialized.
Related
I'm writing tests for an Express CRUD app. The app has an account recovery route that accepts POST requests with an email in the body. It searches for an user with a given email, changes it's password then sends an email with the new password and returns 200.
So I want to write a test that checks if the user's password has indeed changed.
This was my attempt:
First I created a user factory using the factory-girl lib.
// factory.js file
const { factory } = require('factory-girl');
const User = require('../../models/User');
factory.define('User', User, {
email: factory.sequence('User.email', n => `fakeuser${n}#mail.com`),
name: factory.chance('name'),
password: factory.chance('word')
});
module.exports = factory;
Nice. Then I wrote the test:
// One test inside my test suite
it('should return 200 and change user\'s password', async () => {
const user = await factory.create('User');
const oldPassword = user.password;
const response = await request(app)
.post(endpoint)
.send({ email: user.email });
const passwordChanged = oldPassword !== user.password;
expect(response.status).toBe(200);
expect(passwordChanged).toBe(true);
await user.remove();
});
But passwordChanged is always being evaluated to false, since user.password doesn't change at all. I mean, on the database, it changes (the method works correctly), but on my test the user object is not updated after the request.
In other words, what I want to test here is the state of a document in the database, not only what the request is returning. Any suggestions on how to achieve this?
You can open a change stream and listen for when your fields are changed, then run the comparison right then.
I have a controller which I want to test
// user model
const userModel = require('../models/user')
// get user model from handler
const User = userModel.User
function index(req, res) {
User.find(function(err, users) {
if (err) console.log(err)
console.log('debug')
res.render('../views/user/index', {
title: 'User index',
users: users
})
})
}
module.exports = {
index
}
using the following code
// dependencies
const sinon = require('sinon')
// controller to be tested
const controller = require('../controllers/user')
// get user test
describe('test user index', function() {
it ('should return users', function() {
var req = {}
var res = {
render: function() {
sinon.spy()
}
}
controller.index(req, res)
})
})
When I run the test it doesn't execute the console.log('debug') which seems to me indicates that the test can't run the User.find() function. Any help would be appreciated.
As a temporary solution, you can include DB connection string at the top of the file.
Explanation: I guess your controller is part of an app, so it connects to DB on init. However, here you are testing an isolated controller, therefore DB connection isn't initialized yet. That's quick solution, for proper way of doing that refer to official docs
I'm trying to test a router in Node.js app with Jest + Supertest, but my router is making a call to service, which is calling the endpoint:
router.post('/login', async (req, res, next) => {
try {
const { username, password } = req.body;
// I WANT TO MOCK userService.getUserInfo FUNCTION, BECAUSE IT IS MAKING A POST CALL
const identity = await userService.getUserInfo(username, password);
if (!identity.authenticated) {
return res.json({});
}
const requiredTenantId = process.env.TENANT_ID;
const tenant = identity.tenants.find(it => it.id === requiredTenantId);
if (requiredTenantId && !tenant) {
return res.json({});
}
const userResponse = {
...identity,
token: jwt.sign(identity, envVars.getVar(envVars.variables.AUTH_TOKEN_SECRET), {
expiresIn: '2h',
}),
};
return res.json(userResponse);
} catch (err) {
return next(err);
}
});
This is my test that works well:
test('Authorized - respond with user object', async () => {
const response = await request(app)
.post('/api/user/login')
.send(users.authorized);
expect(response.body).toHaveProperty('authenticated', true);
});
this is how getUserInfo function looks like:
const getUserInfo = async (username, password) => {
const identity = await axios.post('/user', {username, password});
return identity;
}
but it executes the method getUserInfo inside a router and this method is making a REST call - I want to mock this method in order to avoid REST calls to other services.
How it could be done?
I've found a mockImplementation function in Jest docs https://jestjs.io/docs/en/mock-function-api.html#mockfnmockimplementationfn
but how I can mock func inside a supertest testing?
You can use jest's auto mocking at the top of your test
like so:
jest.mock('./path/to/userService');
// and include it as well in your test
const userService = require('./path/to/userService');
it will generate a mock of the entire module and every function will be replaced with jest.fn() with no implementation
and then depending on the userService if it's just an object it's getUserInfo method will be a jest.fn() and you can set it's return value like this:
// resolved value as it should return a promise
userService.getUserInfo.mockResolvedValue(mockIdentity);
and the mockIdentity will have to look something like this:
const mockIdentity = {
authenticated: true,
tenants: [
{
id: "x12",
mockInfo: "mock-info-value"
}
],
mother: "Superwoman",
father: "Superman"
})
}
So, as far as I google it, I understood that this problem relevant to async / promise coding. I waste over 2Hr plus with this, but still receive no result. Probably because I'm bad in it. So my identifier.js code is right and works fine, it returns the exact data I want. app.js is still good too. So where is the problem? I can't export result value from identifier.js, because if I do it, I receive 'undefined':
const identifier = require("./db/ops/identifier");
trade_log.create({
Flag: req.body.Flag,
Instrument: req.body.Instrument,
Venue: req.body.Venue,
Price: req.body.Price,
Currency: req.body.Currency,
Quantity: req.body.Quantity,
Counterparty: req.body.Counterparty,
Identifier: identifier(req.body.Counterparty),
Commentary: req.body.Commentary,
but if I export it correcty (according to other guides), just like
let x = identifier(req.body.Counterparty).then(return value);
I receive an error at writing trade_log.create phase.
What is identifier.js? This module is a function that should request data from input form (req.body) via get and receive responce, return data & then in app.js it should be written in to MongoDB (writing works fine, already tested it)
app.js
const trade_log = require("./db/models/trade_log");
const identifier = require("./db/ops/identifier");
app.all('/log', function (req, res, next) {
let x = identifier(req.body.Counterparty.then();
trade_log.create({
Flag: req.body.Flag,
Instrument: req.body.Instrument,
Venue: req.body.Venue,
Price: req.body.Price,
Currency: req.body.Currency,
Quantity: req.body.Quantity,
Counterparty: req.body.Counterparty,
Identifier: x,
Commentary: req.body.Commentary,
},function (err, res) {
if (err) return console.log (req.body) + handleError(err);
console.log(res);
});
next();
});
identifier.js:
const identifier = (name) => {
request(['options, name'], { 'whatever' })
.then(response => {
/code that works fine
let charset = result;
return (charset);
module.exports = identifier;
I already tried in Identifier.js this export methods:
function name(param) {
//code here
}
module.exports = name();
and this:
module.exports = {
function: (name) => {
//code here
}
I also find relevant this SW answer: Asynchronous nodejs module exports but I still can't understand what am I doing wrong.
How should I correct my code accrding to new ES6 standard or should I use another module.exports method?
I have a function as follows:
if(Meteor.isServer) {
Meteor.methods({
addUser: function (newUser) {
check(newUser, { email: String, password: String });
userId = Accounts.createUser(newUser);
return userId;
},
getUser: function (userID) {
check(userID, String);
return Meteor.users.find({_id: userID}).fetch();
}
});
And I am trying to test this function using Mocha:
if (Meteor.isServer) {
let testUser;
describe('Users', () => {
it("Add User", (done) => {
testUser = {email: 'test#test.test', password: 'test'};
try {
testUser._id = Meteor.call('addUser', testUser);
console.log(Accounts.users.find({_id: testUser._id}).fetch());
done();
} catch (err) {
assert.fail();
}
});
it("Get user", (done) => {
try {
Meteor.call('getUser', testUser._id);
done();
} catch (err) {
assert.fail();
}
});
});
And I know that the meteor call with 'addUser' works, because the console.log after that returns the user that I just made and the first test passes when I run it with "meteor test --driver-package practicalmeteor:mocha"
But then I come to the second testing part, where I try to get the user with the meteor call 'getUser', but then I get stuck:
'Cannot call method 'find' of undefined'
Now I know that the difference is that I use 'Meteor.users' instead of 'Account.users' to find the user, but I am totally in the dark what the difference is between these two. Should I replace all the Meteor.users method calls with Accounts.user method calls or not? How would you test this?
I just stumbled on this post, since I have dealt with the same issue some hours ago.
As I can see in your code, your testUser is defined in your first unit ( it("Add User"...){}). I advise you not to use the value from the first unit in the second unit.
You may rather use beforeEach and afterEach to have a clean setup for each unit and then create a new user in the second test unit. You should also clean up your db after each unit:
describe('Users', () => {
// use this for each test
let testUser;
beforeEach(() => {
// let's always create a new clean testUser object
testUser = {email: 'test#test.test', password: 'test'};
});
afterEach(() => {
// Remove the user to keep our db clean
if (testUser._id)
Meteor.users.remove(testUser._id);
});
it("Add User", (done) => {
testUser._id = Meteor.call('addUser', testUser);
const users = Meteor.users.find({_id: testUser._id}).fetch();
const user = users[0];
assert.isNotNull(user);
assert.isDefined(user);
assert.equal(user._id, testUser._id);
done();
});
it("Get user", (done) => {
// get a new id from our previously tested
// (and assume to be working) function
testUser._id = Meteor.call('addUser', testUser);
const user = Meteor.call('getUser', testUser._id);
assert.isNotNull(user);
assert.isDefined(user);
assert.equal(user._id, testUser._id);
done();
});
});
I also found, that your 'getUser' method returns an array, so I changed it to:
getUser: function (userID) {
check(userID, String);
const users = Meteor.users.find({_id: userID}).fetch();
return users[0];
}
All tested and running.