I am testing my app.js using Jest and it says express.urlencoded is not a function.
Im using express 4.16.4 and while I am writing test for app.js that looks somewhat like this
const express = require('express');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(require('./routes'));
module.exports = app;
and my test case is:
jest.mock('express');
it('has a parser', () => {
const app = require('../src/app');
const express = require('express');
expect(app.use).toHaveBeenCalledWith(express.urlencoded());
});
This gives me an error saying: express.urlencoded is not a function.
I expect this test to pass because the app works perfectly fine but only inside the test it says that express.urlencoded is not a function.
You have to manually provide factory and mock module methods there, which you want to test. This would look something like this:
const urlencodedMock = jest.fn();
jest.mock('express', () => {
urlencoded: urlencodedMock,
});
it('has a parser', () => {
const app = require('../src/app');
const express = require('express');
expect(app.use).toHaveBeenCalledWith(urlencodedMock);
});
EDIT:
I am not familiar with express, but you can try something like example below. jest.mock() will mock express in a way that it passes express() and then inside the test when that part is passed, it will mock it again, to provide json() and urlencoded() functions to express.
jest.mock('express', () => {
return {
use: () => {
return;
}
}
});
it('has a parser', () => {
const jsonMock = jest.fn();
const urlencodedMock = jest.fn();
const app = require('../src/app');
jest.doMock('express', () => {
json: jsonMock,
urlencoded: urlencodedMock,
});
expect(app.use).toHaveBeenCalledWith(urlencodedMock);
});
Related
I have an express app:
const express = require('express');
const app = express();
const cors = require('cors');
app.use(cors({ optionsSuccessStatus: 200 }));
app.get('/api/whoami', (req, res) => {
const ipaddress = req.ip;
res.status(200).json({ ipaddress });
});
app.listen(process.env.PORT || 3000);
module.exports = app;
and a test file:
const chai = require('chai');
const chaiHttp = require('chai-http');
const chaiMatch = require('chai-match');
const { describe, it } = require('mocha');
const server = require('../../server');
const should = chai.should();
const { expect } = chai;
chai.use(chaiHttp);
chai.use(chaiMatch);
describe('/GET /api/whoami', () => {
it('should return the IP address', (done) => {
chai.request(server)
.get('/api/whoami')
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.a('object');
res.body.should.have.property('ipaddress');
expect(res.body.ipaddress).should.match(/* very long regex */);
done();
});
});
});
for some reason, I keep geting Uncaught AssertionError: expected Assertion{ __flags: { …(4) } } to match [my very long regex], i didn't find anyone with the same error. How can I get my true ip with express? Or what is the right way to test it?
The syntax is expect(something).to.match and not expect(something).should.match. See docs. Or, if you want to use should, you don't need expect, since the syntax for that is something.should.match.
The fix is therefore to change your code either as follows:
expect(res.body.ipaddress).to.match(/* very long regex */);
...or as follows:
res.body.ipaddress.should.match(/* very long regex */);
In the style guide, you get a good comparison between how to use expect and how to use should.
By mixing those two things, you took expect(...) which returns object that contains things like to and used it as source of your should, so that should.match check operated on the object returned by expect(...) and not the IP address itself.
I need export an object or variable from my app to a router module.
The object is called "page" into "ClientClass".
I read something in SO and I tried to use a global var to save the object, exports it on end of unit.
This object will be used in the router module.
But, I have no success. In the router module "page" is always undefined.
How could I do that?
Main App JS - ClientClass.js:
const express = require('express');
const app = express();
const WARoutes = require('./routes/WARoutes');
var globalpage;
export default class ClientClass {
constructor(options) {
this.options = ...
}
async start() {
const browser = ....
const page = await browser.newPage();
// set globalpage to export
globalpage = page;
console.log('Done!');
app.use(express.json({ limit: '20mb' }));
app.use('/whats', WARoutes);
app.listen(port, () => {
console.log(`Listening on ${this.callbackUrl}...`);
});
}
start();
};
module.exports.page =globalpage;
WARoutes.js:
const express = require('express');
const router = express.Router();
const pagebrowser = require('../ClientClass.js');
const page = pagebrowser.page;
router.get('/getChats', async (req, res) => {
const chats = await page.evaluate((includePict, done) => {
do sometthing; //Here is my problem - page is undefined
}, includePict, done);
res.send(chats);
});
module.exports = router;
You have a cyclical dependency. You need to pass your page variable to the WARoutes.js implementation. Here's one way to do it:
WARoutes.js:
const express = require('express');
const router = express.Router();
//export a function which takes the `page` variable, *returning* the router which used to be _exported_
module.exports = function(page){
router.get('/getChats', async (req, res) => {
const chats = await page.evaluate((includePict, done) => {
do something;
}, includePict, done);
res.send(chats);
});
return router;
}
ClientClass.js:
const express = require('express');
const app = express();
const WARoutes = require('./routes/WARoutes');
export default class ClientClass {
constructor(options) {
this.options = ...
}
async start() {
const browser = ....
const page = await browser.newPage();
console.log('Done!');
app.use(express.json({ limit: '20mb' }));
app.use('/whats', WARoutes(page));
app.listen(port, () => {
console.log(`Listening on ${this.callbackUrl}...`);
});
}
start();
};
P.S.
I am also curious about what you're passing to page.evaluate. The first is a function with two arguments, the second and third are those two arguments again. I have a sneaking suspicion this is not going to work even as modified. You're going to need to provide more information about the page.evaluate API for additional help with that.
I am trying to write a simple case where I am hitting a route and checking the response.
My tests work but every time it also throws this msg:
Jest did not exit one second after the test run has completed.This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
Here is my unit test:
// we will use supertest to test HTTP requests/responses
import request = require('supertest');
import bodyParser1 = require('body-parser');
// we also need our app for the correct routes!
const index = require('./index');
index.use(bodyParser1.json());
index.use(bodyParser1.urlencoded({ extended: true }));
describe('GET / ', () => {
test('Test sample get', async done => {
const response: any = await request(index).get('/');
expect(response.text).toEqual('Welcome to Minos');
expect(response.statusCode).toBe(200);
done();
});
});
afterAll(async done => {
done();
});
and here is my index.ts:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/', (req, res) => {
//res.setHeader('Content-Type', 'text/html');
res.send('Welcome to Minos');
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
module.exports = app;
Did you try this one? I hope this way can solve your problem.
describe('GET / ', () => {
test('Test sample get', async () => {
const response: any = await request(index).get('/');
expect(response.text).toEqual('Welcome to Minos');
expect(response.statusCode).toBe(200);
}, 20000);
});
Also done is not necessary with async/await approach.
I'm new to nodeJS and testing and I'd like to know how I can test my application routes properly. I've read some articles that uses supertest and chai-http to call the POST method but I believe this way would be more of an integration testing instead of unit testing my app.
I've read about Sinon but I'm having a hard time applying it on my code like I don't know what to stub, how I can manipulate the data from the request body so I can cover different branches of my conditional statements. I'm monitoring my code coverage with nyc so I'm also aiming to increase my unit test coverage.
I would appreciate it a lot if someone can guide me on this. Thanks in advance!
server.js
const express = require('express');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.listen(8080, function () {
logger.info('App is now running on port 8080');
});
app.use('/', require('./routes/generateURL.js'));
module.exports = app;
generateURL.js
const express = require('express');
const router = express.Router();
router.post('/generate-url', (req, res) => {
let result = {
status: false
};
const acctId = req.body.accountId;
const baseURL = 'http://somecompany.com/billing/';
const dateToday = new Date();
try {
if (accountId) {
result.status = true;
result.bill = baseURL + acctId + '/' + dateToday;
} else {
throw 'Missing accountId';
}
} catch(err){
console.log(err);
}
return res.send(result);
});
module.exports = router;
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