guys!
I am using Jest and Supertest to test my node server code.
Here is my server.js
// server.js
const config = require('./lib/config')
...
const app = new koa()
...
module.exports = app
I want to mock config.js while I used Supertest, here is my server.test.js
// server.test.js
const supertest = require('supertest-as-promised')
describe('xxxxxx', ()=>{
let app,server
beforeEach(()=>{
jest.mock('lib/config',()=>({
uri: '/path',
apiPrefix: '/prefix'
}))
app = require('server')
})
afterEach(()=>{
server && server.close()
app=null
server=null
})
it('should success', async ()=>{
server || (server = app.listen(0))
const request = supertest(server)
request().get('path/prefix_home').expect(200)
})
})
I have printed config in server.js while running test,but the print information showed that jest.mock did not work(path of lib/config is correct).
Anyone has any idea of mocking config.js in such situation by using Supertest??
Jest appear to resolve paths, so the path you provide while mocking has to be consistent: it should be ./lib/config if server.test.js is located next to server.js. If the files are in different places, you'll need to construct the path accordingly, e.g.
../src/lib/config
if your server.js is in src folder and server.test.js is located in test folder next to src
Related
I have created windows service from nodeJs application using node-windows package. Below is my code.
Main.js
var Service = require('node-windows').Service;
// Create a new service object
var svc = new Service({
name:'SNMPCollector',
description: 'SNMP collector',
script: './app.js',
nodeOptions: [
'--harmony',
'--max_old_space_size=4096'
]
//, workingDirectory: '...'
});
// Listen for the "install" event, which indicates the
// process is available as a service.
svc.on('install',function(){
svc.start();
});
svc.install();
/* svc.uninstall(); */
App.js
const { workerData, parentPort, isMainThread, Worker } = require('worker_threads')
var NodesList = ["xxxxxxx", "xxxxxxx"]
module.exports.run = function (Nodes) {
if (isMainThread) {
while (Nodes.length > 0) {
// my logic
})
}
}
}
Now when I run main.js, it creates a windows service and I can see the service running in services.msc
But, how can I call this run() method which is inside the running service, from any outside application? I couldn't find any solution for this, any help would be great.
You might consider simply importing your run function where you need it and run it there, then there is no need for a windows service or main.js - this assumes that "any outside application" is a Node application.
In your other application you you do the folowing:
const app = require('<path to App.js>');
app.run(someNodes)
For broader usage or if you do need to run it as a service, you could be starting an express (or another webserver) in your App.js with an endpoint that invokes your run function. Then from anywhere else you'll need to make an http call to that endpoint.
App.js
const express = require('express')
const bodyParser = require('body-parser')
const { workerData, parentPort, isMainThread, Worker } = require('worker_threads')
const app = express()
const port = 3000
var NodesList = ["xxxxxxx", "xxxxxxx"]
const run = function (Nodes) {
if (isMainThread) {
while (Nodes.length > 0) {
// my logic
})
}
}
}
app.use(bodyParser.json())
app.post('/', (req, res) => res.send(run(req.body)))
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
(Based off of example for express - https://expressjs.com/en/starter/hello-world.html)
You'll need to install both express and body-parser: $ npm install --save express body-parser from the directory of App.js.
From your other applications you will need to call the endpoint http://localhost:3000 with a POST request and the Nodes as a JSON array.
You can expose it on a port like the other answer mentions, though you'll want to make sure you don't expose it more broadly depending on the environment you're running in. There's a good answer here on ensuring the port is locked down.
As an alternative to exposing it on a port you can simply call the function by running the command in any other application:
node -e 'require("/somePathToYourJS/app").run()'
One concern is that app.js will now run at whatever permissions the calling application has. Although that can be resolved by running runas prior. More details here. But an example is:
runas /user:domainname\username "node -e 'require(^"/somePathToYourJS/app^").run()'"
in server code I have this:
import express from "express";
const server = express();
import path from "path";
// const expressStaticGzip = require("express-static-gzip");
import expressStaticGzip from "express-static-gzip";
import webpack from "webpack";
import webpackHotServerMiddleware from "webpack-hot-server-middleware";
import configDevClient from "../../config/webpack.dev-client";
import configDevServer from "../../config/webpack.dev-server.js";
import configProdClient from "../../config/webpack.prod-client.js";
import configProdServer from "../../config/webpack.prod-server.js";
const isProd = process.env.NODE_ENV === "production";
const isDev = !isProd;
const PORT = process.env.PORT || 8000;
let isBuilt = false;
const done = () => {
!isBuilt &&
server.listen(PORT, () => {
isBuilt = true;
console.log(
`Server listening on http://localhost:${PORT} in ${process.env.NODE_ENV}`
);
});
};
if (isDev) {
const compiler = webpack([configDevClient, configDevServer]);
const clientCompiler = compiler.compilers[0];
const serverCompiler = compiler.compilers[1];
const webpackDevMiddleware = require("webpack-dev-middleware")(
compiler,
configDevClient.devServer
);
const webpackHotMiddlware = require("webpack-hot-middleware")(
clientCompiler,
configDevClient.devServer
);
server.use(webpackDevMiddleware);
server.use(webpackHotMiddlware);
console.log("process.env.NODE_ENV",process.env.NODE_ENV);//RETURNS UNDEFINED
server.use(webpackHotServerMiddleware(compiler));
console.log("Middleware enabled");
done();
} else {
webpack([configProdClient, configProdServer]).run((err, stats) => {
const clientStats = stats.toJson().children[0];
const render = require("../../build/prod-server-bundle.js").default;
server.use(
expressStaticGzip("dist", {
enableBrotli: true
})
);
server.use(render({ clientStats }));
done();
});
}
I client and server config files I have this plugin enabled:
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify("development"),
WEBPACK: true
}
but this is the output
process.env.NODE_ENV undefined
Server listening on http://localhost:8000 in undefined
in client side it is working BUT express side process.env.NODE_ENV returns undefined
Assuming you using Webpack-Dev-Server, you can use this call syntax witch is proper :
const dev = Boolean( process.env.WEBPACK_DEV_SERVER )
You will no longer need to pass environment type parameters, because I think you pass parameters in your script run in packages.json
I'm writing my experience to help anyone out there with this problem, though I did not actually solve it. I had the same problem with setting the environment variables in my server-side project.
apparently, after you set the environment variables they are completely accessible in the building process, which is in the build tools like webpack config or even .babelrc.js.
but after the build process, the environment variables get overwritten AND there is a time gap between build process and overwriting environment variables.
I used many webpack or babel plugins but neither of them could hold on to environment variables after the build process ON the server-side but they were immediately defined on the client-side.
since I'm using ReactJs, I tried adding REACT_APP_ to the beginning of variables, but still no luck.
some other plugins I used: webpack dotenv, webpack.DefinePlugin, webpack.EnvironmentPlugin, babel-plugin-transform-define, babel-plugin-transform-inline-environment-variables
so it made me use the good old-fashion way of setting environment.js on DEPLOY but not on the BUILD process.
in case someone is not familiar: you have one main environment.js and (in my case) 2 other files, one for staging environment.staging.js and one for production environment.prod.js. On each deploy, you copy the related js to environment.js, the main environment file, and in your code, you always read global CONSTs,baseUrl for APIs and ... from environment.js.
hope it helps someone out there.
I am making an express web app and I am unable to import a javascript file.
In board.js, I have a line const utility = require('./utility');. This statement gives an error: ReferenceError: require is not defined.
VSCode suggests to convert const utility = require('./utility'); to an ES6 module. The result after accepting that suggestion is: import { generateRandomData } from './utility';.
If I do this, the previous error goes away but a new error appears SyntaxError: import declarations may only appear at top level of a module.
This is the folder structure of the project:
server.js:
const express = require("express");
const app = express();
const path = require('path');
const PORT = process.env.PORT || 5000
app.listen(PORT, () => {
console.log("server started")
});
app.use(express.static(path.join(__dirname + '/public')))
app.get('/', (req,res) => {
res.sendFile(__dirname + "/index.html")
});
utility.js:
const hello = () => {
console.log('hello');
}
module.exports.hello = hello;
How else am I supposed to import javascript files in board.js?
Your public directory is made static via express.static in your server.js. Therefore, calling a public file from client-side will not pass by express but by the client's browser.
If your JS is played directly within a browser, instead of require you should use import and export.
<script src="utility.js"></script>
I added this line in index.html and it solved the problem.
Edit: Sorry, I thought I pasted the line.
Rather than in the root directory, I want to keep all my backend related files inside a folder named 'server'. The problem is now the frontend won't load properly as it can't find the 'pages' directory. I remember there was a way to set the directory somehow when initializing the app but I don't remember the specifics. Can someone please help me with this?
server/index.js:
const express = require('express')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const app = next({
dev,
// some config property that I don't remember
})
app.prepare().then(() => {
const server = express()
server.listen(3000, () => console.log('> Ready on http://localhost:3000'))
})
You can read from the documentation:
The next API is as follows:
next(opts: object)
Supported options:
dev (bool) whether to launch Next.js in dev mode - default false
dir (string) where the Next project is located - default '.'
quiet (bool) Hide error messages containing server information - default false
conf (object) the same object you would use in next.config.js - default {}
Then, change your start script to NODE_ENV=production node server.js.
It is dir option.
I have a problem with the dotenv package.
My application folder:
|_app_folder
|_app.js
|_password.env
|_package.json
I've of course install dotenv, but when i tried to log a process.env variables, the result is always undefined, please can you help me ?
password.env :
//password.env
CLIENT_ID=xxxxxxxx
app.js :
//app.js
const express = require('express');
const app = express();
const Twig = require("twig");
//Require dotenv
require('dotenv').config();
// Setting the Twig options
app.set("twig options", {
allow_async: true,
strict_variables: false
});
app.get('/', function (req, res) {
//Trying to log it
console.log(process.env.CLIENT_ID);
//
res.render('index.twig', {
date : new Date().toString()
});
});
app.get('/instagram',function(req,res){
// Building the URL
let url = 'https://api.instagram.com/oauth/authorize/?client_id=';
// Redirect to instagram for oauth
res.redirect(url);
})
app.listen(3000, function () {
console.log('Running');
})
Thank you for your time.
By default the dotenv package does only load a file named .env if you want to load another file you need to specify the path
require("dotenv").config({ path: "path/to/file" })
Resources:
https://www.npmjs.com/package/dotenv
I was having somewhat the same problem for a while turns out you just have to put the .env file in the root of the directory (top-most level).
I know this post is old but I just want to make sure no one struggles with such a simple task again.
When using import instead of require. -
You can use -r (require) to preload dotenv. You do not need to require and load dotenv in your application code.
$ node -r dotenv/config app.js
Even though I put the .env file in the root folder, still console.log(process.env.myKey) is undefined. The fix worked for me is I put the path to the env file in the require config itself like below. (It's in the root of the file - so "./.env)
require("dotenv").config({path:"./.env"})
Another important note:
Place your .env file in the root folder, not in /src