I've been trying to figure this out for a while now, but with no luck. I initially had the issue when performing simple integration tests with a MongoDB database, but I've stripped the code right down and made it as simple as I can. The only thing I have running is a single test file:
// blah.test.js
const express = require('express');
const app = express();
describe('test block', () => {
let server = null;
beforeEach(() => {
server = app.listen(3000, () => console.log('Listening on port 3000'));
});
afterEach(async () => {
await server.close();
});
it('should pass the test', () => {
expect(1).toBe(1);
});
});
The test passes, but Jest informs me of an open handle which could prevent it from exiting:
On this occasion, it did exit, but still notices an open handle. I would like to know how to safely close this, without forcing exit. With previous tests, I would get the same open handle warning, but also with an error stating that Jest didn't exit one second after completing the tests.
I also tried using beforeAll() and afterAll(), instead of beforeEach() and afterEach(), but still get the same problem. I know the test doesn't require the server on this occasion, but I was trying to make it as simple as possible to try to find the issue with opening and closing the server.
UPDATE: I noticed that it seems to work fine as soon as I add a second test file:
// blah2.test.js
const express = require('express');
const app = express();
describe('test block', () => {
let server = null;
beforeEach(() => {
server = app.listen(3000, () => console.log('Listening on port 3000'));
});
afterEach(async () => {
await server.close();
});
it('should pass the test', () => {
expect(2).toBe(2);
});
});
No open handles with two tests running
If anyone can share any ideas as to why this happens, it would be much appreciated.
I am using:
Express: 4.16.3
Jest: 23.5.0
NPM: 6.3.0
So I solved the issue by abstracting all the app logic to an app.js file:
const express = require('express');
const routes = require('./routes');
const app = express();
app.use('/api', routes);
module.exports = app
Then creating a server.js file with all my server logic:
const app = require('./app.js')
const PORT = process.env.PORT || 3000
app.listen(PORT, () => console.log(`Listening on port: ${PORT}`))
Then just import app.js into your test file like this:
const app = require('../app.js')
Works like a charm!
I had the same issue and I was able to fix it yesterday. The issue is calling app.listen(). You should avoid calling app.listen in your app.js file or jest test file. Just export the app with routes from app.js. Then, you can use supertest to make the request in your test.
// in your app.js
const app = express();
// add routes and middleware
module.exports = app;
// in your test file
import app from './app.js';
import supertest from 'supertest';
describe('test block', () => {
it('test route', async (done) => {
const res = await supertest(app).get('/').expect(200);
done();
});
});
Try this:
beforeAll(async () => {
// let's create a server to receive integration calls
app = express();
app.get('/', (req, res) => res.send('Hello World!'));
await new Promise((resolve) => {
app.listen(6666, () => {
console.log('Example app listening on port 6666!');
return resolve();
});
});
});
afterAll(() => { console.log('closing...'); app.close(); });
Related
image of the error I am trying to build nft search app that when you give adress it finds the nfts that a wallet has. but i am using alchemy and don't want to expose api key. Don't know backend, using next.js.
my backend code:
const express = require("express");
const axios = require("axios");
const dotenv = require("dotenv");
dotenv.config();
const app = express();
const port = process.env.PORT || 3000;
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.get("/api", (req, res) => {
const apiKey = process.env.API_KEY;
const owner = req.query.owner;
const baseURL = `https://eth-mainnet.g.alchemy.com/nft/v2/${apiKey}/getNFTs/`;
const fetchURL = `${baseURL}?owner=${owner}`;
axios
.get(fetchURL)
.then((response) => {
res.json(response.data);
})
.catch((error) => {
res.json({ error: error.message });
});
});
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
my frontend
const fetchNFTs = async () => {
const response = await fetch(`/api?${wallet}`);
const nfts = await response.json();
setNFTs(nfts);
};
I tried chat gpt, serverless function but I failed to achieve results
Is this a separate Express server? By default Next.js runs on port 3000, and that's why you're making a GET to localhost:3000. But if your Next.js server is started, your custom Express server would pick a different port because the 3000 is going to be taken. So your const response = await fetch('/api?${wallet}'); will result in a 404 because there's no such route in your Next.js app.
You could move your function into a Next.js API handler if you want your backend and frontend to live under the same port. Also you wouldn't need to manually create the express server and take care of the dotenv since Next.js is going to take care of that for you.
Right now, I have app.js where I have my usual code and my socket.io code. But what I want to do is, separate every single code of socket.io into 1 different file and require that socket.io code from the different file into my main app.js. Is there any way to do it writing 2/3 lines of code into my app.js to require socket.io from a different file?
Note: I do not want to write any of my socket.io code into my app.js so I do not know if it would be possible to require('....') it into my app.js from a different file. Ideally want to separate everything within io.on('connection'){}
const express = require('express');
const http = require('http'); // socket.io is created upon http server. A way to create server
const cors = require('cors');
const {Server} = require('socket.io');
const app = express();
app.use(cors());
const server = http.createServer(app); // this is to create http server with express for socket.io
const io = new Server(server, {
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"]
}
});
io.on("connection", (socket) => {
socket.on("newUser", (username) => {
addNewUser(username, socket.id);
console.log('connect print: '); printUsers();
})
socket.on("disconnect", () => {
removeUser(socket.id);
console.log('disconnect print: '); printUsers();
});
})
server.listen(3001, () => {
console.log('server listening on port 3001');
})
There would be a few way to do this but something like below should work.
In your new file, use module.exports to export an object containing any functions or objects you want to export:
//socketio.js
module.exports = {
getIo: (server) => {
const io = new Server(server, {
//...
});
io.on("connection", (socket) => {
//...
}
//your other functions
return io;
}
}
Then in your app.js, require it and use the object's properties:
//app.js
const socketio = require('./socketio.js');
//after creating your server etc
const io = socketio.getIo(server);
im trying to proxy to backend api which is running on port 5000. i have created a custom server.js file for my nextjs app. but its not working im getting 'Application error: a client-side exception has occurred (see the browser console for more information)' error. and when i check the console, indeed the data is not fetching from backend.
server.js:
const express = require('express')
const next = require('next')
const { createProxyMiddleware } = require("http-proxy-middleware")
const port = 3000
const app = next({})
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
server.use('/api/products', createProxyMiddleware({ target:
'http://198.51.100.255:5000', changeOrigin: true }))
server.all('*', (req, res) => {
return handle(req, res)
})
server.listen(port, () => {
console.log(`app running on port ${port}`)
})
})
I a beginner with Express js and when I reload the server to show the HTML file display "Cannot get" this is photo from the console and its show som errors
this my code server-side:
and this is a photo from git bash and the server is working
and this is my HTML code
help, please
Instead of app.route(), use app.get()
like this
const express = require("express)
const path = require("path")
const app= express()
app.get("/",(req,res)=>{
res.sendFile(path.join(__dirname, './index.html'))
})
app.listen(3000,()=>{
console.log("server running at port 3000")
})
app.route takes a string as an argument and returns a single route - you're passing a callback function, so change your route handling to the following:
// use the appropriate HTTP verb
// since you're trying to serve the `index.html` file,
// `get` should be used
app.route("/")
.get((req, res) => {
res.sendFile(path.join(__dirname, './index.html')
})
Alternatively, you could just do the following:
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname, './index.html')
})
Here's a working example:
// thecodingtrain/
// index.js
// home.html
// package.json
const path = require("path")
const express = express()
const app = express()
const PORT = 3000
app.route("/")
.get((req, res, next) => {
res.sendFile(
path.join(__dirname, "./home.html")
)
})
app.listen(PORT, () => {
console.log(`Listening on port ${PORT})
})
Hope this helps.
I have a web app that takes a moment to load - as it needs to connect to a database, and so some other things that take time.
What's the best way to have a temporary loading route in Express?
I'd like to do something like the following:
const express = require('express')
const app = express()
// Temporary / for if someone hits the server before it's finished starting
app.get('/', (req, res) => res.send(`Loading....`))
// In my non-demo app, there's a router here that takes a moment to load, instead of a timeout.
setTimeout(function(){
app.get('/', (req, res) => res.send(`Ready!`))
}, 3 * 1000)
app.listen(3000, () => console.log('Example app listening on port 3000!'))
Routes can't be deleted at runtime, but you can add a middleware that checks if everything is initialized, if it isn't you end the request with: res.send('Loading'); otherwise you go to the next middelware.
let initialized = false;
app.get('/', (req, res, next) => {
if(!initialized)
return res.send('Loading...');
next();
});
app.get('/', (req, res, next) => {
res.send(`Ready!`);
});
setTimeout(() => initialized = true, 3000);
If your app needs some time to load properly, the best option is to NOT let it start the server.
It works very well with i.e. load balancers and multiple containers as they wait for the /health check to pass before they put the container behind the loadbalancer. Which is something you want to do for modern services.
For example this:
import { app } from './app';
import { config } from './config';
import { logger } from './components/ourLog';
import { initPromise } from './components/ourMongo';
const port = config.server.port;
async function startServer() {
await initPromise;
app.listen(port, () => {
logger.info(
{
port,
params: config.params,
processEnv: process.env,
},
'App has started'
);
});
}
startServer()
.catch(err => {
logger.error({ err }, 'Critical error, cannot start server');
process.exit(1);
});
We have component that connects to mongo and it expose initPromise, which is the promise, which is resolved after the connection is sucesfully done and you can start with using the db.
You could ping the server "x" seconds to test when it is ready.
Server
We will create a ready variable, that is set to false, when all of your database, api and other things are done doing what they need you set it to true.
We will also create a route that such as /ping that will respond with the value of ready.
const express = require('express')
const app = express()
let ready = false
// Do database stuff, API stuff, etc.
// Set ready to true when ready
// Temporary / for if someone hits the server before it's finished starting
app.get('/', (req, res) => res.send(`Loading....`))
app.get('/ping', (req, res) => res.json({ready}))
app.listen(3000, () => console.log('Example app listening on port 3000!'))
Client
Here we will ping the server every "x" seconds, I set it to 0.5s, once ping returns true, we cancel the timeout and run the initialization code that builds the page.
let timeout
timeout = setInterval(async () => {
let response = await fetch('/ping')
let ready = await response.json()
if (ready.ready) {
clearInterval(timeout)
loadpage()
}
}, 500)