Ensuring server app runs before mocha tests start - javascript

This is similar to Ensuring Express App is running before each Mocha Test , but the specified solution still isnt working + i'm using a websocket server
in short , i'm using a websocket framework called socketcluster and this is my server file
import {SocketCluster} from 'socketcluster';
const socketCluster = new SocketCluster({
workers:1,
brokers:1,
port: 3000,
appName:null,
initController: __dirname + '/init.js',
workerController: __dirname + '/worker.js',
brokerController: __dirname + '/broker.js',
socketChannelLimit: 1000,
crashWorkerOnError: true
})
export default socketCluster
running node server.js starts the worker process specified in worker.js
export const run = (worker) => {
console.log(' >> worker PID: ',process.pid);
const app = express();
const httpServer = worker.httpServer;
const scServer = worker.scServer;
app.use(cookieParser())
httpServer.on('request', app);
app.get('/',(req,res) => {
console.log('recieved')
res.send('Hello world')
})
}
I want to test the server , but the tests are finishing (and failing) way before the server actually starts. is there a way i can force the server to fully load before going ahead with tests? this is what i have so far
describe('Express server',() =>{
beforeEach((done) => {
require('../../server/server')
done()
})
it('should return "Hello World"',(done) => {
http.get('http://127.0.0.1:3000',(res) => {
expect(res).to.contain('wtf world')
done()
})
})
})
the above doesnt seem to work. the server doesnt fully load in the before block despite providing the done() call as well.
edit - i've tried splitting the server.js file to invoke a different server based on how its imported.
const main = () => {
console.log('main server')
new SocketCluster({
workers:1,
brokers:1,
port: 3000,
appName:null,
initController: __dirname + '/init.js',
workerController: __dirname + '/worker.js',
brokerController: __dirname + '/broker.js',
socketChannelLimit: 1000,
crashWorkerOnError: true
})
}
export const test = (port,done) => {
console.log('testing server')
new SocketCluster({
workers:1,
brokers:1,
port: port,
appName:null,
initController: __dirname + '/init.js',
workerController: __dirname + '/worker.js',
brokerController: __dirname + '/broker.js',
socketChannelLimit: 1000,
crashWorkerOnError: true
})
done()
}
if (require.main === module){
main()
}
and in test.js , i do this - still doesnt seem to work though
import {expect} from 'chai';
import {test} from '../../server/server'
describe('Express server',() =>{
before(function(done){
test(3000,done)
})
it('should return "Hello World"',(done) => {
http.get('http://127.0.0.1:3000',(res) => {
expect(res).to.contain('world')
done()
})
})
})
edit:2 - trie another way by returning a promise from the server.js file. still doesnt work
export const test = (port) => {
console.log('testing server')
return Promise.resolve(new SocketCluster({
workers:1,
brokers:1,
port: port,
appName:null,
initController: __dirname + '/init.js',
workerController: __dirname + '/worker.js',
brokerController: __dirname + '/broker.js',
socketChannelLimit: 1000,
crashWorkerOnError: true
}))
}
and in the before hook
before(function(done,port){
test(3000).then(function(){
console.log('arguments: ',arguments)
done()
})
})

Your server module doesn't have a callback, so it could not be ready when you call done() in your beforeEach method.
First, export your app in your server module.
Then, do something like:
const app = require('../../server/server').app;
let server;
before(done => {
server = app.listen(3000, done);
});
/**
...
your tests here
...
**/
/** and, if you need to close the server after the test **/
after(done => {
server.close(done);
});
This way, done() will be called in the listen callback, so in your tests the server will be listening correctly. Then, remember to close it after tests end (useful if server is required in one or more test suites).

The solution explained here worked for me, in particular:
At the end of server.js ( or app.js ):
app.listen( port, ip, function()
{
console.log( 'Server running on http://%s:%s', ip, port )
app.emit( "app_started" )
})
module.exports = app
and in test.js:
var server = require( '../server' )
before( done =>
{
server.on( "app_started", function()
{
done()
})
})
In this case, app sends an "app_started" event when it is listening, and the test code waits for it. The provided URL contains more details.
Hope it helps !

You need to wait until the server actually listens on the given port.
This could be accomplished by exporting some kind of init function in your server.js, which takes the done callback from mocha.
In your server.js
let initCallback;
[..]
app.listen(port, function() {
if (initCallback) {
initCallback();
}
});
exports = {
init: function(cb) {
initCallback = cb;
}
}
In your test
beforeEach((done) => {
require('../../server/server').init(done)
})
Also see: How to know when node.js express server is up and ready to use

I combined the first two posts and it worked for mine.
First, make sure you have init code in your app.js or server.js
// put this in the beginning of your app.js/server.js
let initCallback;
//put this in the end of your app.js/server.js
if (initCallback) {
// if this file was called with init function then initCallback will be used as call back for listen
app.listen(app.get('port'),"0.0.0.0",(initCallback)=>{
console.log("Server started on port "+app.get('port'));
});
}
else{
// if this file was not called with init function then we dont need call back for listen
app.listen(app.get('port'),"0.0.0.0",()=>{
console.log("Server started on port "+app.get('port'));
});
}
//now export the init function so initCallback can be changed to something else when called "init"
module.exports = {
init: function(cb) {
initCallback = cb;
}
}
Next in your test.js you will need this
//beginning of your code
const app = require("../../server/server").app;
before(done => {
require("../app").init();
done();
});
//end of your code
after(done => {
done();
});
I am no expert in javascript but this works for me. Hope it helps!

Related

How Can I Serve Static Content Alongside Dynamic Routes in A Deno Oak Server

I am used to working with NodeJS and Koa. I've been playing with Deno and have run the example of a static fileserver:
/* static_server.js */
import { Application } from 'https://deno.land/x/oak/mod.ts'
const port = 8080
const app = new Application()
// Error handler middleware
app.use(async (context, next) => {
try {
await next()
} catch (err) {
console.error(err)
}
})
// Send static content
app.use(async (context) => {
console.log(`${context.request.method} ${context.request.url.pathname}`)
await context.send({
root: `${Deno.cwd()}/static`,
index: "index.html",
})
})
await app.listen({ port })
I have also created a dynamic server using routes:
/* routes.js */
import { Application, Router } from 'https://deno.land/x/oak/mod.ts'
const port = 8080
const app = new Application()
const router = new Router()
router.get('/', context => {
context.response.body = 'Hello world!'
})
router.get('/foo', context => {
context.response.body = 'Book Page'
})
router.get('/foo/:thing', context => {
context.response.body = `Foo ${context.params.thing}`
})
app.use(router.routes())
app.use(router.allowedMethods())
await app.listen({ port })
How can I combine these so that I can serve dynamic content but also provide static files such as the stylesheet?
In my Koa code I use the koa-static package:
import serve from 'koa-static'
app.use(serve('public'))
What is the equivalent for an Oak server?
Adding suggested code (thanks Jonas Wilms)
/* static_content.js */
import { Application, Router } from 'https://deno.land/x/oak/mod.ts'
const port = 8080
const app = new Application()
const router = new Router()
router.get('/', context => {
context.response.body = 'Hello world!'
})
router.get('/foo', context => {
context.response.body = 'Book Page'
})
router.get('/foo/:thing', context => {
context.response.body = `Foo ${context.params.thing}`
})
router.get(context => context.send({ root: `${Deno.cwd()}/static` }))
app.use(router.routes())
app.use(router.allowedMethods())
await app.listen({ port })
but this still does not work...
After combining a lot of the information in the comments I managed to get things working:
/* static_content.js */
import { Application, Router, Status } from 'https://deno.land/x/oak/mod.ts'
const port = 8080
const app = new Application()
const router = new Router()
// error handler
app.use(async (context, next) => {
try {
await next()
} catch (err) {
console.log(err)
}
})
// the routes defined here
router.get('/', context => {
context.response.body = 'Hello world!'
})
router.get('/error', context => {
throw new Error('an error has been thrown')
})
app.use(router.routes())
app.use(router.allowedMethods())
// static content
app.use(async (context, next) => {
const root = `${Deno.cwd()}/static`
try {
await context.send({ root })
} catch {
next()
}
})
// page not found
app.use( async context => {
context.response.status = Status.NotFound
context.response.body = `"${context.request.url}" not found`
})
app.addEventListener("listen", ({ port }) => console.log(`listening on port: ${port}`) )
await app.listen({ port })
I know I'm a bit late on the thread, but there are some things I would like to point out.
In Oak 10.1 (the current version at the time of this writing), the send function throws an error if the file it tired to load did not exist. Thus, our static+dynamic server can take on the following form.
import { oak, pathUtils } from './deps.ts'
const app = new oak.Application()
const router = new oak.Router()
app.use(async (ctx, next) => {
try {
await oak.send(ctx, ctx.request.url.pathname, {
root: 'static',
index: 'index.html',
})
} catch (_) {
await next()
}
})
router.get('/dynamic', ctx => {
ctx.response.body = 'dynamic route worked'
})
app.use(router.allowedMethods())
app.use(router.routes())
app.listen({ port: 8000 })
If you want to serve your static files at a certain root path, change the static middleware so that it checks for the root and then omits that root path from the second argument of the send function.
function staticMiddleware(rootPath: string, staticDirectory: string) {
return async (ctx, next) => {
if (!ctx.request.url.pathname.startsWith(rootPath)) return await next()
const newPath = ctx.request.url.pathname.slice(rootPath.length)
if (!newPath.startsWith('/') && newPath.length) return await next()
try {
await oak.send(ctx, newPath, {
root: staticDirectory,
index: 'index.html',
})
} catch (_) {
await next()
}
}
}
app.use(staticMiddleware('/assets', 'static'))
I think you should use the static router at last. Because when use static server first, dynamic router is nonreachable for static router error.
app.use(router.routes())
app.use(router.allowedMethods())
// move the static router down
app.use( async context => {
context.response.status = Status.NotFound
context.response.body = `"${context.request.url}" not found`
})
Not sure whether this is still relevant or already outdated, but as of now (August 2022), there seems to be no general answer to this.
Serving Static Files Alongside Your API Using Oak/Deno
When setting up OpenAPI for an oak-based REST service, I was coming across this issue as well. Requirements were:
Serve openapi.yml statically from /openapi/openapi.yml
Serve a HTML statically from /openapi for convenience
Serve prefixed routers unaffectedly
A straight-forward approach to serve static files from a certain directory under a sub-path of the application is using a middleware and checking the path:
import {
Application, Context, Router
} from 'https://deno.land/x/oak#v11.1.0/mod.ts';
const app = new Application();
const port = 3000;
// Middleware only hooking in and sending static files if prefix matches
// the desired subpath:
const openapi = async (ctx: Context, next: () => Promise<unknown>) => {
const prefix = '/openapi'; // Sub-path to react on
if (ctx.request.url.pathname.startsWith(prefix)) {
await ctx.send({
root: `${Deno.cwd()}/src/openapi/`, // Local directory to serve from
index: 'index.html',
path: ctx.request.url.pathname.replace(prefix, ''), // Map to target path
});
} else {
// If the request does not match the prefix, just continue serving from
// whatever comes next..
await next();
}
};
// This is a dummy API endpoint wrapped into a prefixed router for demo:
const statusRouter = new Router({ prefix: '/status' });
statusRouter.get('/', (ctx: Context) => {
ctx.response.body = {
healthy: true,
ready: true,
};
});
// Boilerplate..
app.use(openapi);
app.use(statusRouter.routes());
app.use(statusRouter.allowedMethods());
app.addEventListener('listen', () => {
console.log(`Listening on localhost:${port}`);
});
await app.listen({ port });
Running this MWE using deno run --allow-net --allow-env --allow-read src/serve.ts, you'll
find the statically served /openapi/openapi.yml,
find the index.html from your local static path served under /openapi (resp. /openapi/ and /openapi/index.html)
find the /status API behaving just normally.
i'm using like that. In html you can provide a path to your file:
<script src="/js/app.js"></script>
then you can use routes to provide what do you want to use on path js/app.js:
import {RouterContext} from 'https://deno.land/x/oak/mod.ts'
const decoder = new TextDecoder("utf-8")// set doecoder
const fileCont = await Deno.readFile('./views/test.js') //getting file conetent
const fileJS = decoder.decode(fileCont) //decoding it
router.get('/js/app.js', (ctx: RouterContext) => { //yep, route can has defferents of real file location
ctx.response.type = "application/javascript"
ctx.response.body = fileJS
})
and whatever you are providing this link somewhere it'll render you file.
Deno REST API

How to export node express app for chai-http

I have an express app with a few endpoints and am currently testing it using mocha, chai, and chai-http. This was working fine until I added logic for a pooled mongo connection, and started building endpoints that depended on a DB connection. Basically, before I import my API routes and start the app, I want to make sure I'm connected to mongo.
My problem is that I'm having trouble understanding how I can export my app for chai-http but also make sure there is a DB connection before testing any endpoints.
Here, I am connecting to mongo, then in a callback applying my API and starting the app. The problem with this example is that my tests will start before a connection to the database is made, and before any endpoints are defined. I could move app.listen and api(app) outside of the MongoPool.connect() callback, but then I still have the problem of there being no DB connection when tests are running, so my endpoints will fail.
server.js
import express from 'express';
import api from './api';
import MongoPool from './lib/MongoPool';
let app = express();
let port = process.env.PORT || 3000;
MongoPool.connect((err, success) => {
if (err) throw err;
if (success) {
console.log("Connected to db.")
// apply express router endpoints to app
api(app);
app.listen(port, () => {
console.log(`App listening on port ${port}`);
})
} else {
throw "Couldnt connect to db";
}
})
export default app;
How can I test my endpoints using chai-http while making sure there is a pooled connection before tests are actually executed? It feels dirty writing my application in a way that conforms to the tests I'm using. Is this a design problem with my pool implementation? Is there a better way to test my endpoints with chai-http?
Here is the test I'm running
test.js
let chai = require('chai');
let chaiHttp = require('chai-http');
let server = require('../server').default;;
let should = chai.should();
chai.use(chaiHttp);
//Our parent block
describe('Forecast', () => {
/*
* Test the /GET route
*/
describe('/GET forecast', () => {
it('it should GET the forecast', (done) => {
chai.request(server)
.get('/api/forecast?type=grid&lat=39.2667&long=-81.5615')
.end((err, res) => {
res.should.have.status(200);
done();
});
});
});
});
And this is the endpoint I'm testing
/api/forecast.js
import express from 'express';
import MongoPool from '../lib/MongoPool';
let router = express.Router();
let db = MongoPool.db();
router.get('/forecast', (req, res) => {
// do something with DB here
})
export default router;
Thank you for any help
After receiving some good feedback, I found this solution works best for me, based on Gomzy's answer and Vikash Singh's answer.
In server.js I'm connecting to the mongo pool, then emitting the 'ready' event on the express app. Then in the test, I can use before() to wait for 'ready' event to be emitted on the app. Once that happens, I'm good to start executing the test.
server.js
import express from 'express';
import bodyParser from 'body-parser';
import MongoPool from './lib/MongoPool';
let app = express();
let port = process.env.PORT || 5000;
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
(async () => {
await MongoPool.connect();
console.log("Connected to db.");
require('./api').default(app);
app.listen(port, () => {
console.log(`Listening on port ${port}.`)
app.emit("ready");
});
})();
export default app;
test.js
//Require the dev-dependencies
import chai from 'chai';
import chaiHttp from 'chai-http';
import server from '../src/server';
let should = chai.should();
chai.use(chaiHttp);
before(done => {
server.on("ready", () => {
done();
})
})
describe('Forecast', () => {
describe('/GET forecast', () => {
it('it should GET the forecast', (done) => {
chai.request(server)
.get('/api/forecast?type=grid&lat=39.2667&long=-81.5615')
.end((err, res) => {
res.should.have.status(200);
done();
});
});
});
});
Express app is an instance of EventEmitter so we can easily subscribe to events. i.e app can listen for the 'ready' event.
Your server.js file will look like below,
import express from 'express';
import api from './api';
import MongoPool from './lib/MongoPool';
let app = express();
let port = process.env.PORT || 3000;
app.on('ready', function() {
app.listen(3000, function() {
console.log('app is ready');
});
});
MongoPool.connect((err, success) => {
if (err) throw err;
if (success) {
console.log('Connected to db.');
// apply express router endpoints to app
api(app);
// All OK - fire (emit) a ready event.
app.emit('ready');
} else {
throw 'Couldnt connect to db';
}
});
export default app;
Just create a function below to connect to mongo and, make it returns a promise.
then use await to wait for it to connect and return. the function could be like that
function dbconnect(){
return new Promise(function(resolve, reject){
MongoPool.connect((err, success) => {
if (err) reject(err);
if (success) {
resolve({'status' : true})
} else {
reject(new Error({'status' : false}))
}
})
})
}
And then, use
await dbconnect();
api(app);
app.listen(port, () => {
console.log(`App listening on port ${port}`);
})
now await line will wait for the function to connect to DB and then return success or error in case of failure.
This is a kind of solution you can use, but I would not recommend you to do this, what we actually do is.
create services and use those services in routes, don't write DB code directly in routes.
and
while writing tests for routes mock/stub those services, and test services separately in other test cases, where you just pass DB object and service will add functions on that DB objects, so in tests you can connect to DB and pass that object to those services to test functions, it will give you additional benefit, if you want to use dummy/test DB for testing you can set that in test cases.
Use Before function in your tests like below :
describe('Forecast', () => {
before(function(done){
checkMongoPool(done); // this function should wait and ensure mongo connection is established.
});
it('/GET forecast', function(cb){
// write test code here ...
});
});
And you can check mongodb connection like this below methods:
Method 1: just check the readyState property -
mongoose.connection.readyState == 0; // not connected
mongoose.connection.readyState == 1; // connected`
Method 2: use events
mongoose.connection.on('connected', function(){});
mongoose.connection.on('error', function(){});
mongoose.connection.on('disconnected', function(){});
You can use running server instead of a express instance.
Start your server with a private port, then take tests on the running server.
ex: PORT=9876 node server.js
In your test block, use chai.request('http://localhost:9876') (replace with your protocol, server ip...) instead of chai.request(server).
If you're using native mongodb client you could implement reusable pool like:
MongoPool.js
// This creates a pool with default size of 5
// This gives client; You can add few lines to get db if you wish
// connection is a promise
let connection;
module.exports.getConnection = () => {
connection = MongoClient(url).connect()
}
module.exports.getClient = () => connection
Now in your test you could,
const { getConnection } = require('./MongoPool')
...
describe('Forecast', () => {
// get client connection
getConnection()
...
In your route:
...
const { getClient } = require('./MongoPool')
router.get('/forecast', (req, res) => {
// if you made sure you called getConnection() elsewhere in your code, client is a promise (which resolves to mongodb connection pool)
const client = getClient()
// do something with DB here
// then you could do something like client.db('db-name').then(//more).catch()
})

MongoConnect passing in client as the callback

I'm confused about the callback here. We return the client in the promise, but how are we executing that in the callback? If the client object is the callback then isn't the client calling the client? What is the callback equivalent to?
const mongodb = require('mongodb');
const MongoClient = mongodb.MongoClient;
const mongoConnect = callback => {
MongoClient.connect(
'mongodb+srv://<user>:<password>#cluster0-ntrwp.mongodb.net/test?retryWrites=true'
)
.then(client => {
console.log('Connected!');
callback(client);
})
.catch(err => {
console.log(err);
});
};
module.exports = mongoConnect;
(app.js)
mongoConnect(client => {
console.log(client);
app.listen(3000);
});
Isn't this the expected output. I'm a little confused about the callback here.
const mongodb = require('mongodb');
const MongoClient = mongodb.MongoClient;
const mongoConnect = client => {
console.log(client);
app.listen(3000); => {
MongoClient.connect(
'mongodb+srv://<user>:<password>#cluster0-ntrwp.mongodb.net/test?retryWrites=true'
)
.then(client => {
console.log('Connected!');
client => {
console.log(client);
app.listen(3000);(client);
})
.catch(err => {
console.log(err);
});
};
module.exports = mongoConnect;
(app.js)
mongoConnect(client => {
console.log(client);
app.listen(3000);
});
I'm guessing you're asking how the 1st code works. I rewrote the 1st code to use old school function() instead of the ES6 fat arrow and put in some logging to make it clearer what's going on:
const express = require('express');
const mongodb = require('mongodb');
const MongoClient = mongodb.MongoClient;
const app = express();
function mongoConnect(callback) {
MongoClient.connect('mongodb://localhost:27017')
.then(client => {
console.log('[mongoConnect] Connected!');
console.log('[mongoConnect] callback type: ' + typeof(callback));
console.log('[mongoConnect] client type: ' + typeof(client));
console.log('[mongoConnect] client is: ' + client.constructor.name);
callback(client);
})
.catch(err => {
console.log(err);
});
};
mongoConnect(function(client) {
console.log('[main] client type: ' + typeof(client));
console.log('[main] client is: ' + client.constructor.name);
app.listen(3000, function() {
console.log('[main] listening on 3000');
});
});
Running the code:
[mongoConnect] Connected!
[mongoConnect] callback type: function
[mongoConnect] client type: object
[mongoConnect] client is: MongoClient
[main] client type: object
[main] client is: MongoClient
[main] listening on 3000
As to your question:
If the client object is the callback then isn't the client calling the client? What is the callback equivalent to?
To unravel what's going on:
client is an object, and callback is a function.
mongoConnect() accepts a function as parameter.
The function that gets passed into mongoConnect() accepts client (an object) as parameter. Technically this is not needed. I think this is only there for audit/logging purposes. You can remove all mentions of client in that part of the code and see that it still works.
For example, you can change that bit of code to be:
mongoConnect(function() {
app.listen(3000, function() {
console.log('[main] listening on 3000');
});
});
and it will still work the same way.
The execution sequence is:
mongoConnect(function(client)) is called
Inside mongoConnect, MongoClient.connect() is called
Once connected, the callback (function(client)) is called
The callback executes app.listen()
This flow sequence ensures that the database is connected before the app goes to listen mode. Without this, the app can listen before any database connection is confirmed (e.g. due to slower than expected database connection, etc.). You can confirm this flow by observing that [mongoConnect] log lines are always printed before any [main] log lines.

Execute a Node.js child process after clicking a button

At the moment I have a code in Node.js which calls the program "EnergyPlus". Unfortunately I have to start an external console and execute the Node.js file "manually". However, I would like to be able to press a button in the front end of my application that starts the "EnergyPlus" plus program.
Here is my Node.js file:
var spawn = require('child_process').spawn,
child = spawn('C:\\EnergyPlusV9-0-1\\EP-Launch.exe', ["C:/Windows/System32/Drivers/etc/hosts"]);
child.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
child.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
child.on('close', function (code) {
console.log('child process exited with code ' + code);
});
Is there a way to integrate this code within a button or to execute this code after clicking a button?
Thank you very much in advance!
Here's how you can do this:
On client side button click, make a request to a certain path in your express API
Your express API handles the request by launching the program
Code something that looks like this:
client.html:
<button onclick="func()">start app</button>
<script>
const func = () => fetch('http://your.api.url/some/path');
</script>
server.js:
// imports
const express = require('express');
const spawn = require('child_process').spawn;
// create server
const app = express();
// upon request to the launch path, launch the program
app.get('/some/path', (req, res) => {
let child = spawn(
'C:\\EnergyPlusV9-0-1\\EP-Launch.exe',
["C:/Windows/System32/Drivers/etc/hosts"]
);
// etc (rest of the code you wrote)
// response. You can modify this to send a custom response to your client
res.send('');
})
Thank you very much for the help!
I have found the solution for my problem.
To start from the beginning, within my application I work with React and Webpack. To solve my problem, I structured my Server.js file (where I set up the Express behavior) in the following way:
const express = require('express');
const app = express();
const port = process.env.PORT || 5000;
const fs = require("fs")
const spawn = require('child_process').spawn;
// console.log that your server is up and running
app.listen(port, () => console.log(`Listening on port ${port}`));
app.use(cors())
// create a GET route
app.get('/express_backend/:filename', (body, res) => {
const f = body.params.filename;
// open EnergyPlus Programm with a specific file which is stored localy
let child = spawn(
'C:\\EnergyPlusV9-0-1\\EP-Launch.exe',
[process.cwd()+"src/"+ f + ".idf"]
);
child.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
child.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
child.on('close', function (code) {
console.log('child process exited with code ' + code);
});
res.send('EnergyPlus is running');
});
// default options
app.use(fileUpload());
//post the uploaded file into the local storage
app.post('/upload', function(req, res) {
...
}
// The name of the input field (i.e. "sampleFile") is used to retrieve the uploaded file
let sampleFile = req.files.file;
// Use the mv() method to place the file localy
fs.writeFile(__dirname + `/upload/${sampleFile.name}`, sampleFile.data,
(err) => {
....
})
});
Like Nino Filiu mentioned in his post, I integrated the child spawn function into the server.js. First, I call the EP launch.ex with the specific file, I stored localy (this function is not part of this answer). "C:\EnergyPlusV9-0-1\EP-Launch.exe"is the path to EnergyPlus. "[process.cwd()+"src/"+ f + ".idf"]" helps EnergyPlus to open the local stored fiel directl.
So the important thing regarding my problem was the app.get, which I trigger within my App.js.
In App.js I call the spawn child process like this:
class App extends Component {
constructor(props){
super(props)
this.state = {filename: null}
};
componentDidMount() {
...
};
callBackendAPI = async () => {
...
};
//trigger the spawn child function within server.js
startEnergyPlus = (e) =>{
fetch (`http://localhost:5000/express_backend/${this.state.filename}`, {
method: "GET"
});
render(){
return(
<div className="App">
<button onClick={this.startEnergyPlus}>start app</button>
</div>
};
And that is it. Hopefully, it is clear and helpfull. If not, please leave a comment!

Mocha API Testing: getting 'TypeError: app.address is not a function'

My Issue
I've coded a very simple CRUD API and I've started recently coding also some tests using chai and chai-http but I'm having an issue when running my tests with $ mocha.
When I run the tests I get the following error on the shell:
TypeError: app.address is not a function
My Code
Here is a sample of one of my tests (/tests/server-test.js):
var chai = require('chai');
var mongoose = require('mongoose');
var chaiHttp = require('chai-http');
var server = require('../server/app'); // my express app
var should = chai.should();
var testUtils = require('./test-utils');
chai.use(chaiHttp);
describe('API Tests', function() {
before(function() {
mongoose.createConnection('mongodb://localhost/bot-test', myOptionsObj);
});
beforeEach(function(done) {
// I do stuff like populating db
});
afterEach(function(done) {
// I do stuff like deleting populated db
});
after(function() {
mongoose.connection.close();
});
describe('Boxes', function() {
it.only('should list ALL boxes on /boxes GET', function(done) {
chai.request(server)
.get('/api/boxes')
.end(function(err, res){
res.should.have.status(200);
done();
});
});
// the rest of the tests would continue here...
});
});
And my express app files (/server/app.js):
var mongoose = require('mongoose');
var express = require('express');
var api = require('./routes/api.js');
var app = express();
mongoose.connect('mongodb://localhost/db-dev', myOptionsObj);
// application configuration
require('./config/express')(app);
// routing set up
app.use('/api', api);
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('App listening at http://%s:%s', host, port);
});
and (/server/routes/api.js):
var express = require('express');
var boxController = require('../modules/box/controller');
var thingController = require('../modules/thing/controller');
var router = express.Router();
// API routing
router.get('/boxes', boxController.getAll);
// etc.
module.exports = router;
Extra notes
I've tried logging out the server variable in the /tests/server-test.js file before running the tests:
...
var server = require('../server/app'); // my express app
...
console.log('server: ', server);
...
and I the result of that is an empty object: server: {}.
You don't export anything in your app module. Try adding this to your app.js file:
module.exports = server
It's important to export the http.Server object returned by app.listen(3000) instead of just the function app, otherwise you will get TypeError: app.address is not a function.
Example:
index.js
const koa = require('koa');
const app = new koa();
module.exports = app.listen(3000);
index.spec.js
const request = require('supertest');
const app = require('./index.js');
describe('User Registration', () => {
const agent = request.agent(app);
it('should ...', () => {
This may also help, and satisfies #dman point of changing application code to fit a test.
make your request to the localhost and port as needed
chai.request('http://localhost:5000')
instead of
chai.request(server)
this fixed the same error message I had using Koa JS (v2) and ava js.
The answers above correctly address the issue: supertest wants an http.Server to work on. However, calling app.listen() to get a server will also start a listening server, this is bad practice and unnecessary.
You can get around by this by using http.createServer():
import * as http from 'http';
import * as supertest from 'supertest';
import * as test from 'tape';
import * as Koa from 'koa';
const app = new Koa();
# add some routes here
const apptest = supertest(http.createServer(app.callback()));
test('GET /healthcheck', (t) => {
apptest.get('/healthcheck')
.expect(200)
.expect(res => {
t.equal(res.text, 'Ok');
})
.end(t.end.bind(t));
});
Just in case, if someone uses Hapijs the issue still occurs, because it does not use Express.js, thus address() function does not exist.
TypeError: app.address is not a function
at serverAddress (node_modules/chai-http/lib/request.js:282:18)
The workaround to make it work
// this makes the server to start up
let server = require('../../server')
// pass this instead of server to avoid error
const API = 'http://localhost:3000'
describe('/GET token ', () => {
it('JWT token', (done) => {
chai.request(API)
.get('/api/token?....')
.end((err, res) => {
res.should.have.status(200)
res.body.should.be.a('object')
res.body.should.have.property('token')
done()
})
})
})
Export app at the end of the main API file like index.js.
module.exports = app;
We had the same issue when we run mocha using ts-node in our node + typescript serverless project.
Our tsconfig.json had "sourceMap": true . So generated, .js and .js.map files cause some funny transpiling issues (similar to this). When we run mocha runner using ts-node. So, I will set to sourceMap flag to false and deleted all .js and .js.map file in our src directory. Then the issue is gone.
If you have already generated files in your src folder, commands below would be really helpful.
find src -name ".js.map" -exec rm {} \;
find src -name ".js" -exec rm {} \;
I am using Jest and Supertest, but was receiving the same error. It was because my server takes time to setup (it is async to setup db, read config, etc). I needed to use Jest's beforeAll helper to allow the async setup to run. I also needed to refactor my server to separate listening, and instead use #Whyhankee's suggestion to create the test's server.
index.js
export async function createServer() {
//setup db, server,config, middleware
return express();
}
async function startServer(){
let app = await createServer();
await app.listen({ port: 4000 });
console.log("Server has started!");
}
if(process.env.NODE_ENV ==="dev") startServer();
test.ts
import {createServer as createMyAppServer} from '#index';
import { test, expect, beforeAll } from '#jest/globals'
const supertest = require("supertest");
import * as http from 'http';
let request :any;
beforeAll(async ()=>{
request = supertest(http.createServer(await createMyAppServer()));
})
test("fetch users", async (done: any) => {
request
.post("/graphql")
.send({
query: "{ getQueryFromGqlServer (id:1) { id} }",
})
.set("Accept", "application/json")
.expect("Content-Type", /json/)
.expect(200)
.end(function (err: any, res: any) {
if (err) return done(err);
expect(res.body).toBeInstanceOf(Object);
let serverErrors = JSON.parse(res.text)['errors'];
expect(serverErrors.length).toEqual(0);
expect(res.body.data.id).toEqual(1);
done();
});
});
Edit:
I also had errors when using data.foreach(async()=>..., should have use for(let x of... in my tests

Categories

Resources