const express = require("express");
const app = express();
const router = express.Router();
router.get('/postp',(req,res)=>{
res.status(200);
})
app.listen(PORT, () => {
console.log(`Connected to PORT : ${PORT}`);
});
module.exports = app;
Test case :
const chai = require('chai');
const request = require('supertest');
const app = require('../app');
const post = require('../router/post');
const expect = chai.expect;
describe('Blog',function(){
it('get blogs', function(done){
const response = request(app).get('/postp');
expect(response.status).to.be.equal(200);
done();
})
})
What's the problem?
please specify, is it because I can't access app or something else.
why it's not running
Try using request from chai.
const chai = require('chai');
const request = require('supertest');
const app = require('../app');
const post = require('../router/post');
const expect = chai.expect;
describe('Blog',function(){
it('get blogs', function(done){
const response = chai.request(app).get('/postp')
.end((err, res) => {
res.should.have.status(200);
})
done();
})
})
I suggest you to check this link, it gives more details about assertion lib and chai.
Related
I'm getting the error Cannot Get / while running my code. I've tried researching and can't really find anything that fits my code. Script:
const express = require('express');
const app = express();
const roblox = require('noblox.js');
const bodyParser = require('body-parser');
require('dotenv').config();
roblox.setCookie(process.env.cookie);
const jsonParser = bodyParser.json();
app.post('/pass', jsonParser, async(req, res) => {
let username = req.body.user;
let userid = await roblox.getIdFromUsername(username);
console.log('Working!')
await roblox.setRank(process.env.groupId, userid, "Trainee");
});
let listener = app.listen(process.env.PORT, async () => {
console.log('Your app is currently listening on port: '
+ listener.address().port);
});
Needed to add this code and it didn't give me the error anymore.
app.get('/', (req, res) => {
res.send('Got');
})
I'm trying to stub auth.session when testing endpoint /allowUser2 on an express server app.js.
//--auth.js--
module.exports.session = (req, res, next) => {
req.user = null;
next();
};
//--app.js--
const express = require('express');
const auth = require('./auth');
const app = express();
app.use(auth.session);
app.get('/allowUser2', (req, res) => {
if (!req.user) return res.status(401).send();
if (req.user.user === 2) return res.status(200).send();
});
app.listen(4001).on('listening', () => {
console.log(`HTTP server listening on port 4001`);
});
module.exports = app;
If I just have this one test file test1.js in my test suite, auth gets stubbed successfully.
//--test1.js--
let app;
const sinon = require('sinon');
const auth = require('../../auth.js');
const chai = require('chai');
const chaiHttp = require('chai-http');
const { expect } = chai;
chai.use(chaiHttp);
let agent;
describe('should allow access', () => {
before(async () => {
// delete require.cache[require.resolve('../../app.js')]; // causes Error: listen EADDRINUSE: address already in use
sinon.stub(auth, 'session').callsFake((req, res, next) => {
req.user = { user: 1 };
next();
});
app = require('../../app.js');
agent = chai.request.agent(app);
});
after(async () => {
auth.session.restore();
});
it('should not allow access', async function () {
const response = await agent.get('/allowUser2');
expect(response.status).to.be.equal(200);
});
});
However, if I have more than one test file that requires app.js then I have a problem. If app.js was already required in another test file, such as test2.js below, node doesn't reload app.js when it's required again in test1.js. This causes app.js to call the old auth.session function, not the new stubbed one. So the user isn't authenticated and the test fails.
//--test2.js--
const chai = require('chai');
const chaiHttp = require('chai-http');
const app = require('../../app.js');
const { expect } = chai;
chai.use(chaiHttp);
const agent = chai.request.agent(app);
describe('route /allowUser2', () => {
it("shouldn't allow access", async function () {
const response = await agent.get('/allowUser2');
expect(response.status).to.be.equal(401);
});
});
I tried to reload the app.js by using delete require.cache[require.resolve('../../app.js')];. This worked when reloading a file with a plain function, but when the file is a server like app.js this causes an error: Error: listen EADDRINUSE: address already in use.
Recreate:
download Repo
npm i
npm test
How do you stub a function on the server?
One solution is turn app.js into a function that starts the server on a port number passed in as an argument. Then change the port randomly when requiring. I do not like this option because there may be some reason to keep the app on a specific port.
app.js
const express = require('express');
const auth = require('./auth');
module.exports = (port) => {
const app = express();
app.use(auth.session);
app.get('/allowUser2', (req, res) => {
if (!req.user) return res.status(401).send();
if (req.user.user === 2) return res.status(200).send();
});
app.listen(port).on('listening', () => {
console.log(`HTTP server listening on port ${port}`);
});
return app;
};
when requiring
app = require('../../app.js')((Math.random() * 10000).toString().slice(0, 4));
Instead of exporting the app in app.js, I export a function that launches the server and returns the server instance and app. By exporting the server instance I have the ability to close the server. The app is needed to pass into chai. Make sure const app = express(); is in this function and not before it or it won't recreate.
const express = require('express');
const auth = require('./auth');
const port = 4000;
module.exports = () => {
const app = express();
app.use(auth.session);
app.get('/allowUser2', (req, res) => {
if (!req.user) return res.status(401).send();
if (req.user.user === 2) return res.status(200).send();
});
app.post('/allowUser2', (req, res) => {
if (!req.user) return res.status(401).send();
if (req.user.user === 2) return res.status(200).send();
});
return {
server: app.listen(port).on('listening', () => {
console.log(`HTTP server listening on port ${port}`);
}),
app,
};
};
Then in my tests I can launch the server in before and close the server in after in both tests.
let app;
const sinon = require('sinon');
const auth = require('../../auth.js');
const chai = require('chai');
const chaiHttp = require('chai-http');
const { expect } = chai;
chai.use(chaiHttp);
let server;
describe('route /allowUser2', () => {
before(async () => {
// delete require.cache[require.resolve('../../app.js')]; // causes an error: `Error: listen EADDRINUSE: address already in use`.
sinon.stub(auth, 'session').callsFake((req, res, next) => {
req.user = { user: 2 };
next();
});
server = require('../../app.js')();
agent = chai.request.agent(server.app);
});
after(async () => {
server.server.close(() => {
console.log('Http server closed.');
});
auth.session.restore();
});
it('should allow access', async function () {
const response = await agent.get('/allowUser2');
expect(response.status).to.be.equal(200);
});
});
const chai = require('chai');
const chaiHttp = require('chai-http');
const { expect } = chai;
chai.use(chaiHttp);
let server;
let agent;
describe('route /allowUser2', () => {
before(async () => {
server = require('../../app.js')();
agent = chai.request.agent(server.app);
});
after(async () => {
server.server.close(() => {
console.log('Http server closed.');
});
});
it("shouldn't allow access", async function () {
const response = await agent.get('/allowUser2');
expect(response.status).to.be.equal(401);
});
});
working repo
UPDATE: Proposed Solution https://github.com/DashBarkHuss/mocha_stub_server/pull/1
One problem is the way you are using a direct method reference in app.js prevents Sinon from working. https://gist.github.com/corlaez/12382f97b706c964c24c6e70b45a4991
The other problem (address in use) is because each time we want to get a reference to app, we are trying to create a server in the same port. Breaking that app/server creation into a separate step alleviates that issue.
Am new to jest, node and express, and am having a problem with testing my app.
The actual code seems to be working - it's just when passing the server instance to each of the test files (user.test.js and genres.test.js) and running jest, the port is being blocked. I assume it's because I'm creating duplicate instances of the server in each test file, without realising it.
Running jest with the flag --runInBand works, and so does only using one test file, but this doesn't help me understand exactly what's going on.
I've posted example code below, but I'm struggling to cut it down, however I do think most of the code is irrelevant, and it's just down to how I'm passing the server to each file.
Again, apologies for the length, but I think it should be very basic for anyone but me! Thanks.
index.js (.)
const express = require('express');
const app = express();
const genres = require('./routes/genres');
const users = require('./routes/users');
app.use(express.json());
app.use('/api/genres', genres);
app.use('/api/users', users);
const port = process.env.PORT || 3000;
const server = app.listen(port, () => console.log(`Listening on port ${port}...`));
console.log(typeof server);
// export server to be used in test file
module.exports = server;
genres.js (./routes)
const express = require('express');
const router = express.Router();
router.post('/', async (req, res) => {
res.send('post genre ok');
});
module.exports = router;
users.js (./routes)
const express = require('express');
const router = express.Router();
router.post('/', async (req, res) => {
res.send('post user ok');
});
module.exports = router;
genres.test.js (./tests)
const request = require('supertest');
let server;
describe('auth tests', () => {
const exec = async function(){
return await request(server)
.post('/api/genres');
};
beforeEach(() => {
server = require('../index');
});
afterEach(async () => {
await server.close();
});
describe('POST /', () => {
it('should return 200', async () => {
const res = await request(server).post('/api/genres');
expect(res.status).toBe(200);
});
});
});
user.test.js (./tests)
const request = require('supertest');
let server;
describe('user tests', () => {
const exec = async function(){
return await request(server)
.post('/api/user');
};
beforeEach(() => {
server = require('../index');
});
afterEach(async () => {
await server.close();
});
describe('POST /', () => {
it('should return 200', async () => {
const res = await request(server).post('/api/users');
expect(res.status).toBe(200);
});
});
});
Hopefully this (point 2) helps others with this question
It has worked for me, by splitting the app from the server. I'm not sure if this is the right approach, and I'm not 100% sure why it works with the app rather than the server, but all my tests are now passing.
index.js is now app.js:
const express = require('express');
const app = express();
const genres = require('./routes/genres');
const users = require('./routes/users');
app.use(express.json());
app.use('/api/genres', genres);
app.use('/api/users', users);
// export server to be used in test file
module.exports = app;
The server is separated into another file:
const app = require('./app');
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on port ${port}...`));
and then the test files import the app rather than the server. therefore each test doesn't create its own instance.
NB: I think - I don't really know how correct this is, but as mentioned, it works
I'm trying to test the GET request on the home root '/'. The route doesn't exist in my file root.js because
I want that the test fails but it always succeeds.
I don't understand why. There are 3 files: ./test/test.js, ./server/server.js and ./server/routes/index.js
/*File: ./test/test.js */
/* eslint-env mocha */
const chai = require('chai')
const chaiHttp = require('chai-http')
const { expect } = chai
const app = require('../server/server.js')
chai.use(chaiHttp)
describe('GET Home', () => {
it('Should return Not found', () => {
chai
.request(app)
.get('/', (err, res) => {
const result = res.statusCode
expect(result).to.equal(200)
})
})
})
/*File: ./server/server.js */
const express = require('express')
const bodyParser = require('body-parser')
const config = require('./config.js')
const mainRoutes = require('./routes')
const app = express()
app.set('view engine', 'jade')
app.use(bodyParser.urlencoded({ extended: false }))
app.use(mainRoutes)
app.listen(config.port, () => {
console.log(`The application is running on localhost:${config.port}`)
})
module.exports = app
/*File: ./server/routes/index.js*/
const express = require('express')
const router = express.Router()
// router.get('/', (req, res) => {
// res.render('home')
// })
module.exports = router
This is because get run async, you need to call done() for assertion expect(result).to.equal(200) to get checked, otherwise your test will always passed no matter your router exists or not. Checkout this page and search Caveat if you want to know more.
describe('GET Home', () => {
it('Should return Not found', (done) => {
chai
.request(app)
.get('/')
.end(function (err, res) {
const result = res.statusCode
expect(result).to.equal(200)
done()
})
})
})
Getting error Uncaught TypeError: Cannot read property 'apply' of undefined
at Immediate. (node_modules/express/lib/router/index.js:618:14)
Server and test files.
// server js file
'use strict';
var express = require('express'); // call express
var app = express();
var port = process.env.PORT || 8080;
// Routes for schedule API
var router = express.Router();
router.get('/', function(req, res, next) {
res.json({"msg":'Hello, World!'});
});
app.listen(port);
console.log('Application running on port ' + port);
module.exports=router;
// test.js
var chai = require('chai');
var chaiHttp=require('chai-http');
var server = require('../server');
var should = chai.should();
chai.use(chaiHttp);
describe('Scheduler', function () {
it('should return hello world', function (done) {
chai.request(server)
.get('/')
.end(function (err, res) {
res.should.have.status(200);
done();
};
});
});
Could anybody help me to track what went wrong here?
You can use expect instead of should it's more easier
var chai = require('chai'), chaiHttp = require('chai-http');
chai.use(chaiHttp);
var expect = chai.expect;
app.get('/check', function(req, res) {
//exemple
expect(req.query.ip,"IP Adress Mismatch").to.be.an.ip;
}