I am trying to test a nodejs app with supertest, and I cannot get a single route to run. I've narrowed the problem down. In my test file, I start with this:
var app = express(); // this is the problem, this isn't really the app, right?
// testing this dummy works fine, but I want the real one
app.get('/user', function(req, res){
res.status(200).json({ name: 'tobi' });
});
describe('GET /user', function(){
it('respond with json', function(done){
request(app)
.get('/user')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200, done);
})
})
...and this test passes. But of course, that dummy /user route is not the one I want to test. I want to test routes defined in my "real" app, defined at ./server.js.
Even if I simply move the dummy app.get('/user', function... definition to my "real" server.js file, the one that I launch with nodemon, this simple test fails with a 404.
So what does this line really do: var app = express();, and how do I get hold of the app configured in my server.js file so I can test it?
You need to export your app from server.js. Once you do this, you can require the app in your test files.
server.js
var express = require('express')
var app = express();
// Your routes here...
// At end of file
module.exports = app;
test.js (in a test directory)
var api = require('../server.js'),
request = require('supertest')(api);
describe('noshers', function() {
it('doesn\'t allow GET requests', function(done) {
request
.get('/foo')
.expect(405, done);
});
});
Related
I think I am missing some concept with basic routing for Express. See here
I created some simple test code as follows in my server index.js file.
app.get('/foo', function (req, res) {
console.log('foo path found');
res.send('foo achieved')
})
In my browser(chrome) URL I type
localhost:3000/foo
to trigger the route but I get no response on the server or client.
I verified localhost:3000 is up and running.
Port is set in a different file as follows:
app.set('port', (process.env.PORT || 3000));
But also I get confirmation in the terminal as follows:
const server = app.listen(app.get('port'), () => {
console.log('DEBUG: express: server up');
});
I am on a campus network that blocks some traffic, but b.c. this is localhost I don't think it should matter.
I don't think you're supplying enough information to correctly debug your issue.
I'd initially ensure that Express is listening on port 3000, double-check this line:
app.listen(3000);
Ideally, this line should be at the bottom of the script.
Response to edit: Yes, this should not matter. localhost is an alias for the system itself. It's a loopback, similar to that of 127.0.0.1.
It seems like you have created two express app, as you have mentioned that you are using two different files, the localhost which you are able to run is the one which has app.listen() code, but this doesn't have the app.get()
I suggest you use a single file for now and try doing it.
Try out the following code, and check now with localhost:3000/foo.
const express = require('express')
const app = express()
const port = 3000
app.get('/foo', function (req, res) {
console.log('foo path found');
res.send('foo achieved')
})
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
I'm learning about Dependency Injection and trying to use it in a simple nodejs app. This application has to fetch some data with an external API. Using DI in that case was simple, I just added the dependency as a parameter of the function and it worked like a charm.
async function foo(URL,get_data){
var bar = await get_data(URL);
return bar;
}
When the application is running, get_data would be the function that does the real request and when unit testing my app it would be a dummy function.
How do I apply this same methodology for ExpressJS?
I want it to access the database when is using the application and dummy data when it is testing, but I can't figure out how because I'm not dealing with properties of functions anymore.
In this example:
// index.js
const express = require('express');
const app = express();
const PORT = process.env.PORT || 5000;
var db = require('./model/db')
app.get('/users',(req,res) =>{
db.get_users(function(users){
res.send(users);
})
});
app.listen(PORT, () => console.log(`Server listening to port: ${PORT}`));
module.exports = app;
I need to use the real db when the server is running and a mock one when testing with supertest.
// index.text.js
const request = require('supertest');
const app = require('index');
describe("GET /user", function(){
it('should respond with a json', function(done){
request(app)
.get('/users')
.expect('Content-Type',/json/)
.expect(200,done);
});
});
Problem - I am not able to get any response from postman when hitting localhost:9000. It should give me a user json back which is in my routes file only for time being. Instead it spits out the following.
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="text/javascript" src="/static/js/main.ce2f0561.js"></script>
</body>
Setup
Using create-react-app with express to connect.
My folder structure is
--src React app lives in this
--server
-- index.js
-- express.js
-- controllers
-- routes
-- rs_notes.js
rs_routes.js
'use strict';
module.exports = function(router){
const notesController = require('../controllers/cs_notes');
router.route('/', function(req, res, next) {
// Comment out this line:
//res.send('respond with a resource');
// And insert something like this instead:
res.json([{
id: 1,
username: "samsepi0l"
}, {
id: 2,
username: "D0loresH4ze"
}]);
});
};
express.js
const express = require('express');
const morgan = require('morgan');
const path = require('path');
const app = express();
const router = express.Router();
// Setup logger
app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] :response-time ms'));
// Serve static assets
app.use(express.static(path.resolve(__dirname, '..', 'build')));
require('./routes/rs_notes')(router);
// Always return the main index.html, so react-router render the route in the client
router.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
});
module.exports = app;
index.js
'use strict';
const app = require('./express');
const PORT = process.env.PORT || 9000;
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}!`);
});
Full project link - https://drive.google.com/file/d/0B35OQMkRo3KcSHlkeXdWVjVjc0U/view?usp=sharing
My questions or doubts are
Am I passing the router in a right way. We used to pass app in this
way prior to express 4 ? So not sure if same structure works here.
I am able to load it in browser by hitting localhost:9000 (server is run by node server command as configured) but not in postman.
I was able to fix up this stack by learning the use of Router appropriately and moving some code here and there. But it was still not working for base route i.e when I simply do router.get('/', ...). Gives the same error message. So I rather reversed the approach of connecting node and react. I published my efforts on medium for the same reason as two separate posts.
https://medium.com/#kushalvmahajan/i-am-about-to-tell-you-a-story-on-how-to-a-node-express-app-connected-to-react-c2fb973accf2
Introduction
I have built some back end functionality in Node (First time using Node). Problem is that the whole thing was built in one page (index.js) so now im following a few basic tutorials and setting out express router middleware and now trying to follow a modular MVC approach,
This code is simple but brakes when I separate into two pages Server.js and config.js. I know its a simple problem but i cant spot it. can someone help spot the problem and maybe improve the structure ?
Problem
I go to http://localhost:8080/about or a different route and I get
Cannot GET /about
rather than the correct print out.
back-end/server.js
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;
// get an instance of router
var router = express.Router();
// START THE SERVER
// ==============================================
app.listen(port);
console.log('Server has started!! ' + port);
back-end/config.js
router.use(function(req, res, next) {
console.log(req.method, req.url);
next();
});
router.get('/', function(req, res) {
res.send('im the home page!');
});
// sample route with a route the way we're used to seeing it
router.get('/sample', function(req, res) {
res.send('this is a sample!');
});
router.get('/about', function(req, res) {
res.send('im the about page!');
});
app.route('/login')
.get(function(req, res) {
res.send('this is the login form');
})
.post(function(req, res) {
console.log('processing'); // shows on console when post is made
res.send('processing the login form!'); // output on postman
});
app.use('/', router);
As #SLaks said in his comment, you need to import (require) your backend/config.js file. But it's not as simple as that...
In node, variables are scoped to the file in which they appear, so if you simply add require('./config') to your server.js file, that's not going to work either, because the router variable in config.js is local to that file - it's not going to know about the router variable in server.js.
The solution to this is to have the config.js file export a function which the server.js file can use to configure stuff. For example
config.js
module.exports = function(router) {
// set up your router here with router.use, etc.
};
server.js
var configure = require('./config');
// after you set up your express router...
configure(router);
// now start listening
I have the following test:
describe('Testing the GET methods', function() {
it('Should be able to get the list of articles', function(done) {
// Create a SuperTest request
request(app).get('/api/articles/')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res) {
res.body.should.be.an.Array.and.have.lengthOf(1);
res.body[0].should.have.property('title', article.title);
res.body[0].should.have.property('content', article.content);
done();
});
});
it('Should be able to get the specific article', function(done) {
// Create a SuperTest request
request(app).get('/api/articles/' + article.id)
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200)
.end(function(err, res) {
res.body.should.be.an.Object.and.have.property('title', article.title);
res.body.should.have.property('content', article.content);
done();
});
});
});
Which produces this following error:
any ideas what might be the issue? I have all dependencies checked and installed and required.
EDIT:
The reason this happens is this: https://github.com/Oreqizer/mean-book/blob/master/server.js - lines 11 to 18.
My tests start BEFORE the app connects to the db. I noticed this by console.logging 'app', as well as noticing that
Server running at http://localhost:3000/
gets logged at different times during the first test.
How do I make mocha wait for the app to be defined before running the tests?
OK so it goes like this:
newer version of 'mongoose' causes express not to have a defined 'db' connection before i do var app = express(db); . However, if I add the code that goes:
db.connection.on('connected', callback);
where in the callback I define app , the test gets executed without app being defined.
I really don't know how to fix this besides having two different versions, one for test environment and one for development/production.