Test async with Jest - node.js

Hello? I'm from brazil.
Can you help me with a test? I'm the whole day trying to execute correct and nothing works.
In nutshell, i tried evertying that i saw on internet, but nothing really works.
The follow code was one of the first attempts
const responseToken = await request(app)
.post("/sessions")
.send({ email: "gustavo#gmail.com", password: "gustavo" });
// .send({ email: "admin#admin.com", password: "admin" });
const { token } = responseToken.body;
const userResponse = await request(app)
.post("/users")
.set({ Authorization: Bearer ${token} })
.send({
email: "testIntegration#test.com.br",
name: "Test ",
lastName: "Integration",
password: "test",
});
expect(userResponse).rejects.toEqual(
new AppError("User is not an Admin!")
);
});```
Git: https://github.com/gustavogmfarias/iffolha-js-backend/tree/feature/CreateUser

Okay, I see.
You wrote next code:
expect(userResponse).rejects.toEqual(
new AppError("User is not an Admin!")
);
But on previous step you have already resolved promise with response body from supertest.
Supertest just make a external request to your server and resolve object with response and HTTP Status Code. It doesn't matter what kind of error was throw on your backend.
You should change strategy of code testing. You should check json schema of your response not an error.
For example:
const userResponse = await request(app)
.post("/users")
.set({ Authorization: Bearer ${token} })
.send({
email: "testIntegration#test.com.br",
name: "Test ",
lastName: "Integration",
password: "test",
});
expect(userResponse.body).toEqual({
status: 403,
message: "User is not an Admin!",
});
Please read API of supertest - https://www.npmjs.com/package/supertest
But if you want to check that specific function of your app reject error AppError you should write unit tests for your function and/or create spies - https://jestjs.io/ru/docs/jest-object#jestspyonobject-methodname

Related

Can't receive valid test on specific test controller

I'm testing a sign-in controller and therefore I've written the following test:
it("return 200 when user signed in successfully", async () => {
await request(app)
.post("/api/v1/signup")
.send({
name: "some-name",
email: "test#mail.com",
password: "abcdefg",
})
.expect(StatusCodes.CREATED);
await request(app).post("/api/v1/signin")
.send({
name: "some-name",
email: "test#mail.com",
password: "abcdefg",
});
.expect(StatusCodes.OK);
});
The test code is straightforward. When the two controllers are tested in postman, everything work well and when start to test in jest, I receive bad request when a user try to sign in. The reason for this bad request is because when try to find an user by email in the signin controller, I receive null which I really don't understand what is the cause of this result.
What I must take into account to resolve this issue when testing in jest?
After doing a deep research into this problem, I had realised that when I use the supertest post-request to save particular data into an user collection, this doesn't seems to work. A workaround for this problem is to import the user-model to create particular data into the collection.
Updated Code
it("return 200 when user signed in successfully", async () => {
await new User({
name: "some-name",
email: "test#mail.com",
password: "abcdefg",
}).save();
const response = await request(app)
.post("/api/v1/signin")
.send({
name: "some-name",
email: "test#mail.com",
password: "abcdefg",
});
expect(response.status).toBe(StatusCodes.OK);
});

How to automate testing a user journey?

I use NodeJS for the web server and Mocha for testing. I tried this test to ensure that the application can create a user, log it out, and sign it in again:
const request = require('supertest');
const app = require('../app');
const req = request(app);
describe("user journey", function() {
it("tests a user journey (signup, logout, sign in)", function(done) {
let signedInStub = "something only for logged in users";
req
.post("/signup")
.send({
"email": "test#test.com",
"password": "abcd1234"
})
.expect(function(response) {
expect(response.body.includes(signedInStub))
})
.get("/logout")
.expect(function(response) { // <-- Test fails here.
!response.body.includes(signedInStub)
})
.post("/login")
.send({
"email": "test#test.com",
"password": "abcd1234"
})
.expect(function(response) {
response.body.includes(signedInStub)
})
.get("/content/2")
.expect(200, done);
});
});
I run it with mocha --exit test.js and get the error:
1) user journey
tests a user journey (signup, logout, sign in):
TypeError: Cannot read property 'expect' of undefined
How can I test on the command-line that a user can create an account, log out, and log in?
Create an agent and use that across multiple requests to persist the session.
If needed, install chai, which works with supertest, with npm install --save chai. (See here for details about testing in NodeJS with Mocha and Chai.)
If you are using an auth type other than cookies, persist the data in a variable in the same way and send it with each request.
const request = require('supertest');
const app = require('../app');
const { expect } = require('chai')
const User = require('../models/user');
const email = "test#test.com";
describe("user journey", function() {
let req
let signedInStub = "something only for logged in users"
before(function(){
req = request.agent(app)
})
it("should signup a new test#test.com user", async function() {
// Delete this email in case emails are unique in the database.
await User.deleteOne({email: email});
const response = await req.post("/signup")
.send({
"email": email,
"password": "abcd1234"
})
.redirects(1); // optional, in case your back-end code uses a redirect after signing up.
// Log the response so you can track errors, e.g. hidden parameters in the HTML form that are missing from this POST request in code.
console.log(response.text);
expect(response.text).to.include(signedInStub)
})
it("should logout the new user", async function() {
const response = await req.get("/logout")
expect(response.text).not.to.include(signedInStub)
})
it("should login the new user", async function() {
const response = await req.post("/login")
.send({
"email": email,
"password": "abcd1234"
})
expect(response.text).to.include(signedInStub)
})
it("should get the new users content", async function() {
await req.get("/content/2")
.expect(200)
});
});

How to resolve Mongoose broken authentication

Hey this should be very simple for you nodejs gods, I am trying to make authentication system with nodejs using mongoose so the server is successfully receiving the email and parameters entered in the front-end but it seems as if somewhere in my in my logic I am not doing everything properly can I please get some assistance in handling this error because what happens when I console log on the back-end I get the following.
User Successfully Found
EMAIL: test1#gmail.com
PASSWORD: test1
SIGNINUSER: undefined
I get that User Successfully found even when I entered a wrong user
**Interesting part is when I remove the .then I get back the user object but return errors with regards to unhandled promise
Code below where I am handling the signing in of users
router.post("/signin", async (request, response) => {
const signinUser = await User.find({
email: request.body.email,
password: request.body.password,
})
.then((response) => {
console.log("User Successfully Found");
})
.catch((error) => {
console.log("User Does not exist");
});
//Here I was trying to check if I really am receiving the data from the client
//Just to find that I am receiving the clients data
console.log("EMAIL: ", request.body.email);
console.log("PASSWORD: ", request.body.password);
//Here I was trying to check if the usersInfo is being set inside the siginUser variable
//just to find that I getting the value of undefined
console.log("SIGNINUSER: ", signinUser);
if (signinUser) {
response.status(200).json({
_id: signinUser.id,
name: signinUser.name,
email: signinUser.email,
isAdmin: signinUser.isAdmin,
token: getToken(user),
});
} else {
response.status(401).send({ message: "Invalid Email or Password" });
}
});
Without running the code I would say you are mixing await with then and monoogose queries. So in the proposed solution User.find() returns the query (which is not a promise but a theneable), you exec it to get a promise and await for result. Removing then but keeping your code behavior might look like.
router.post("/signin", async (request, response) => {
const signinUser = await User.find({
email: request.body.email,
password: request.body.password,
}).exec();
if (!signinUser) {
console.log("User Does not exist");
return response.status(401).send({ message: "Invalid Email or Password" });
}
console.log("User Successfully Found");
console.log("EMAIL: ", request.body.email);
console.log("PASSWORD: ", request.body.password);
console.log("SIGNINUSER: ", signinUser);
return response.status(200).json({
_id: signinUser.id,
name: signinUser.name,
email: signinUser.email,
isAdmin: signinUser.isAdm
token: getToken(user),
});
});
I hope it helps.
More info here
Mongoose - What does the exec function do?
Just change your response Code i think this problem will be Gone
return response.status(200).json({
_id: signinUser.id,
name: signinUser.name,
email: signinUser.email,
isAdmin: signinUser.isAdm,
token: getToken(user.toObject()),
});
I changed Only
token: getToken(user.toObject()),

axios is not implementing post request

i am trying to post data with axios (NodeJS, ReactJS) but i ended up getting this errors
and here is my posting code
axios({
method: 'post',
url: '/api/signup',
data:
{
username: this.state.username,
name: this.state.name,
surname: this.state.surname,
email: this.state.email,
password: this.state.password,
confirm_password: this.state.confirm_password,
}
})
.then(res => res.data)
.then(url => window.location.href = url.location)
.catch(error => this.setState({errorBol: true, errorMessage: error}))
and my nodeJS code
router.post('/', async (req,res)=>{
const username = req.body.username;
const name = req.body.name;
const surname = req.body.surname;
const email = req.body.email;
const password = req.body.password;
const confirm_password = req.body.confirm_password;
console.log(username)
console.log(name)
console.log(surname)
console.log(email)
console.log(password)
console.log(confirm_password)
res.status(200).send({location: '/'})
})
i have config for /api/signup like this
router.use('/api/main', require('./sinupfilename'))
so problem is not in router.post('/')
about problem:
i am implementing post request form submission and have a validation for form and it works perfectly but it gives me an errors above when i click submit button so if anyone know clue, i will be glad to hear it
Looks like the issue is not with axios but with your render function. The above issue comes when you are trying to render any object instead of a valid react element.
The issue might be at setState for errorMessage variable. Try printing the errorMessage or typeof errorMessage for further info. It should not be an object.
The error is an javascript object if you read the official documentation for axios.
You need to extract the error message and set it in your errorMessage variable. It should work fine. As per the docs, the same can be done is this similar manner:
const err = ""
if (error.response) {
err = error.response.data
} else if (error.request) {
err = error.request.response
} else {
err = error.message
}
this.setState({errorBol: true, errorMessage: err})
Basically, any thing which needs to be rendered has to be valid react element like string, html tags, numbers but not object. So, you need to make sure that whatever is rendered, it needs to be a valid react element. You can read more about it here
Hope it helps, revert for any doubts.

Getting "Error: the string "Not a valid BCrypt hash." was thrown, throw an Error :)" during Mocha ExpressJS testing

I have a MEAN stack app that is using Passport for authentication.
I'm trying to write a unit test that logs in and checks whether you are redirected to the root (/). However, whenever I run Mocha I get the following error message:
1) POST /home Login test should redirect to / after login:
Error: the string "Not a valid BCrypt hash." was thrown, throw an Error :)
Here's my unit test LoginSpec.js:
var should = require("should");
var app = require("../app");
var mongoose = require("mongoose");
var User = mongoose.model("User");
var request = require("supertest");
var agent = request.agent(app);
...
describe('POST /home', function() {
before(function(done) {
user = new User({
email: "john#email.com",
firstName: "John",
lastName: "Doe",
password: "strongPassword",
username: "johndoe"
});
user.save(done);
})
describe('Login test', function() {
it ('should redirect to / after login', function(done) {
agent.post('/login')
.send({
username: 'johndoe',
password: 'strongPassword'
})
.end(function(err, res) {
done();
})
})
after(function(done) {
User.remove().exec();
return done();
})
})
})
Do I need to BCrype my password? If so, how do I do this?
Also, how come some of the online examples I'm seeing for logging in don't do it? Such as NodeJS/Passport - Testing user login with mocha and superagent and How to authenticate Supertest requests with Passport?
It happen because your password field on database have just a string, not a hashed string.
It must be like $2a$08$LMXAGOARNn4XmnC/rQuhfujrWVwgK/RuHuGpLtXvcv/yruY1v3yXa but probably are just the original password.
I thought I'd answer this since I had the same issue and could not find anywhere with a direct answer.
Where you are defining a new user you will need to use bcrypt to encrypt that password, also when you are login in you will then need to use bcrypt to compare the password to the one saved in the user you have fetched. Otherwise you will continue to get the issue of "Not a valid BCrypt hash.".
Here is a simple encrypt and compare function that I use in my app
UserSchema.methods.encryptPassword = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(10));
}
UserSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.password);
}
More information can be found here: https://www.npmjs.com/package/bcrypt

Resources