Auth0 login before Mocha/Chai test - NodeJS - javascript

I'm attempting to test a NodeJS app using Mocha and Chai. I'm using Auth0 to handle the login and signups for the app. I want to be able to test that, once logged in, the user can visit a set of pages, however I'm having trouble handling the actual logging in.
The .get('/login') redirects me to the Auth0 login page, as I expect. However, despite the .send(userCredentials) providing valid login details, it doesn't seem to login. After login, I expect it to redirect to 'localhost:3000/user' but as far as I can tell the final redirect is to the Auth0 login URL, and I'm unsure if this redirect is what prevents the send, or if the fact that the redirect takes a second or two could be causing the issue.
My test file is below.
var chai = require("chai");
var chaiHTTP = require("chai-http");
var chaiAP = require("chai-as-promised");
var server = require("../app");
var listing = require('../models/RDSModel');
var should = chai.should();
var expect = chai.expect;
var request = require("supertest");
const {Client} = require('pg');
var config = require('../config');
const connection = {
user: 'Admin',
host: process.env.DB_URL,
database: 'postgres_test',
password: config.postgresPass,
port: 5432,
};
var pg = require('knex')({
client: 'pg',
connection: connection,
searchPath: ["knex", "public"]
});
chai.use(chaiHTTP);
chai.use(chaiAP);
describe("Listing.js", function() {
beforeEach("login before each test", function(done) {
const userCredentials = {
email: 'hello#email.co.uk',
password: 'this_is_a_password!'
};
request(server)
.get('/login')
.send(userCredentials)
.end(function(err, res) {
console.log(res);
expect(res).to.have.status(302);
expect(res.body.state).to.be.true;
res.body.data.should.be.an("object");
done();
})
});
describe("get /", function() {
it("#return 200 status code", function(done) {
this.timeout(5000);
chai.request(server)
.get('/Listing/')
.end(function(err, res) {
console.log(res.body);
expect(res).to.have.status(200);
expect('Location', '/Listing')
expect(res.body).to.be.an("object");
done();
})
})
});
describe("get /Ignore", function() {
it("should return 200 status code", function(done) {
this.timeout(5000);
chai.request(server)
.get('/Listing/Ignore')
.end(function(err, res) {
expect(res).to.have.status(200);
expect(res.body).to.be.an("object");
done();
})
})
})
describe("get /Report", function() {
it("should return 200 status code", function(done) {
this.timeout(5000);
chai.request(server)
.get('/Listing/Report')
.end(function(err, res) {
expect(res).to.have.status(200);
expect(res.body).to.be.an("object");
done();
})
})
})
})
The reason it gives for failure is:
1) Listing.js
"before each" hook: login before each test:
Uncaught AssertionError: expected undefined to be true
at Test.<anonymous> (test/test-listing.js:44:41)
at Test.assert (node_modules/supertest/lib/test.js:181:6)
at localAssert (node_modules/supertest/lib/test.js:131:12)
at /Users/<Name>/Documents/Node/NodeStuff/node_modules/supertest/lib/test.js:128:5
at Test.Request.callback (node_modules/supertest/node_modules/superagent/lib/node/index.js:728:3)
at IncomingMessage.<anonymous> (node_modules/supertest/node_modules/superagent/lib/node/index.js:916:18)
at IncomingMessage.EventEmitter.emit (domain.js:476:20)
at endReadableNT (_stream_readable.js:1183:12)
at processTicksAndRejections (internal/process/task_queues.js:80:21)
The body of res is empty, as is the text, which seems odd to me.
Any help would be appreciated.

You are trying to integrate your test suite to an interactive login route. What you actually need is non-interactive login. With Auth0, this can be achieved by POST oauth/token endpoint You will need user's email as well as the verification code sent to that email address ( so that you cannot use unverified emails ) and client secret:
https://auth0.com/docs/api/authentication#authenticate-user
Or, you can use the Management Token obtained by Management API to execute actions.

Related

How to test an API that requires authorization [Mochajs, Chai]

I am testing CRUD API-Operations (https://api.sap.com/api/OP_API_MAINTNOTIFICATION/overview?ReleaseInfo=2021%20FPS02), with mochajs and chai.
let chai = require("chai");
let chaiHttp = require("chai-http");
//Assertion Style
chai.should();
chai.use(chaiHttp);
describe("API TEST", function () {
it.only('Get all notifications', function (done) {
const url = "https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap/API_MAINTNOTIFICATION/MaintenanceNotification";
/**/
chai.request(url)
.post('/auth/sign_in')
// send user login details
.send({
'user': 'ExampleEmail',
'password': 'ExamplePassword'
})
.end(function (err, res) {
var token = res.body.token;
console.log(token);
done();
});
chai.request(url)
.get('')
.set("Authorization", "Bearer " + token)
.end(function (err, res) {
done();
});
});
});
Issue
In order to test the GET function it is required for the user to authorize oneself
{"fault":{"faultstring":"Failed to resolve API Key variable request.header.apikey","detail":{"errorcode":"steps.oauth.v2.FailedToResolveAPIKey"}}}
I did the authorization in this manner / gotten the token but it doesn't work yet(the token is empty), as well as the path "/auth/sign_in" seemingly isn't working
Questions
How to do the Authorization for an API in mochajs in order to test said API ?
The answer to the question has been found.
Send the following authorization with any CRUD Operation:
.auth('Username', 'Password')
Credit: Setting Basic Auth in Mocha and SuperTest #yves-m

How do I unit test a function that needs a cookie with Jest?

I'm very new to testing and I can't figure out how to test this scenario. I use supertest and Jest for testing. In my Express app I use jwt authentication. I store a jwt token that identifies a user in a http only cookie, and it's been created when a user creates and account or logs in.
Now, I have a route that is responsible for a password change requested by a user:
router.post('/reset-password', async function (req, res, next) {
try {
//relevant to the question part here
//
const { userToken } = req.cookies
if (!userToken) {
res.status(401).json({ error: 'unauthorized' })
return
}
const { email } = jwt.verify(userToken, process.env.JWT_SECRET)
/////////////////////
} catch (err) {
res.status(401).json({ error: 'unable to verify' })
}
})
As I understand, in order to test this function, I need to set a cookie in beforeAll. I tried doing so by registering a user that normaly sets required token. Here is my test code:
const request = require('supertest')
const app = require('../app')
const MongoClient = require('mongodb').MongoClient
const client = new MongoClient(`mongodb://localhost:27017/img-test`, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
beforeAll(async () => {
await client.connect()
app.locals.db = client.db('img-test')
await request(app).post('/register').send({
username: 'Bob',
email: 'bob#email.com',
password: 'Hardpass0!',
checkboxTerms: 'on',
'g-recaptcha-response': 'asdasd',
})
})
describe('Password reset', () => {
test('Should reset password', async () => {
await request(app)
.post('/api/account/reset-password')
.send({
passwordCurrent: 'Hardpass0!',
passwordNew: 'Hardpass1!',
})
.expect(200)
})
})
afterAll(async () => {
let db = app.locals.db
await db.dropDatabase()
client.close()
})
And of course, it fails. userToken is going to be undefined because as I understand supertest is not setting an http only cookie when a user is registered, and there is no token on req.cookies? How do I test this scenario? What am I doing wrong? Thanks for help.

How to test Node redirection with Jest

I am using Jest to test my Node REST API.
The problem I have currently is that when I try testing my POST routes, I always receive a status code of 302 due to res.redirect("/").
Example of my POST route:
app.post("/login", async (req, res) => {
try {
let username = 'example'
...
return res.redirect("/");
} catch (error) {
return res.redirect("/");
}
});
jest test file:
'use strict';
const request = require('supertest');
const app = require('./index');
...
describe('Test', () => {
test('POST /login', () => {
return request(app)
.post('/login')
.set('username','example')
.expect(?)
});
});
How can I test that the page has redirected successfully?
As per the Express docs, you can specify a response code as such:
res.redirect(301, 'http://example.com')
The docs state "If not specified, status defaults to “302 “Found”."
Edit: HTTP codes 301 and 302 indicate successful redirection; 301 is permanent and 302 is temporary. Both are "successful" as far as a computer is concerned.
I assert the response.headers.location for redirection location. This way I can write test cases by mocking a single class function that causes different redirections.
test('Should handle "/redirectUri"', async () => {
const exchangeForAuthTokenSpy = jest.spyOn(
OAuth.prototype,
'exchangeForAuthToken',
)
exchangeForAuthTokenSpy.mockResolvedValue({
success: true,
access_token: 'access_token',
})
const app = server('', AuthRoutes)
const res = await request(app).get('/redirectUri?code=code&state=state')
expect(exchangeForAuthTokenSpy).toHaveBeenCalledTimes(1)
expect(exchangeForAuthTokenSpy).toHaveBeenCalledWith('code', 'state')
expect(res.status).toEqual(301)
expect(res.headers.location).toContain(
'/callback?code=200&token=access_token',
)
})
It is late, but could help someone. You can test like below
it('redirection test', function (redirect) {
request(app)
.get('/url')
.expect(302, redirect)
});

Reload express server before some mocha tests E66+

I am building some API endpoints using node/Express and have some problems testing the endpoints.
The problem is that the server needs to be restarted (to clear data stored in memory) between tests.
What is the proper way to restart the Express server amid tests or split the tests to multiple instances?
currently, the following does not work:
it('Admin can login', () => {
chai
.request(server)
.post(`${ROOT_URL}/auth/login`)
.send({
username: 'admin',
password: 'admin'
})
.end((err, res) => {
console.log(res);
expect(res.status).eq(200);
});
});
// need to kill and resart server here
it('Registered user can login', () => {
chai
.request(server)
.post(`${ROOT_URL}/auth/login`)
.send(newUser)
.end((err, res) => {
expect(res.status).eq(200);
expect(res.body.message).eq(
`successful login as ${newUser.username}`
);
});
});

NodeJs Mocha Not Connecting to Database

I am trying to create some unit tests with Mocha and Chai but I am unable to connect to the mysql server. Here I have my unit test:
process.env.NODE_ENV = 'test';
let chai = require('chai');
let chaiHttp = require('chai-http');
let server = require('../app');
let should = chai.should();
chai.use(chaiHttp);
describe('API endpoint /authenticate', function () {
before((done) => {
/* Todo: Clean up Database*/
done()
});
it('should authenticate a user given CORRECT username/password', (done) => {
let user = {
username: 'ax850',
password: 'test'
};
chai.request(server)
.post('/api/authenticate')
.send(user)
.end((err, res) => {
res.should.have.status(200);
done();
});
done();
});
});
As you can see, I am doing a POST request. Then in the script where I handle this POST request, I am connecting to a mySQL server like so:
const db = require('./../../db_conn');
And in the db_conn I have:
const mysql = require('mysql');
const config = require('config.json')('./config.json');
let db;
const db_config = config.a_c.dbConfig;
function connectDatabase() {
if (!db) {
db = mysql.createConnection({
host: db_config.host,
user: db_config.user,
port: db_config.port,
database: process.env.NODE_ENV === 'test' ? db_config.db_test : db_config.db_dev,
//database: db_config.db_dev,
password: db_config.password
});
db.connect(function(err){
if(!err) {
console.log('Database is connected!');
} else {
console.log('Error connecting database!');
}
});
}
return db;
}
module.exports = connectDatabase();
However, when I run my test command: mocha --timeout 10000, it doesn't connect to the database. The mysql.createConnection runs unsuccessfully but doesn't give an error either. Any ideas? This works when I run the server without testing.
You are calling done before the request finishes.
chai.request(server)
.post('/api/authenticate')
.send(user)
.end((err, res) => {
res.should.have.status(200);
done();
});
// this is executed before chai.request is fulfilled
done();

Categories

Resources