How to execute Node .JS APIs test cases using Jenkinsfile - node.js

I am new to Jenkins. I have a small Node .JS server and the test cases are written using Mocha(Integration test cases, not unit test cases). I am trying to create a CI Pipeline for this using Jenkins. My Jenkinsfile looks as follows:
#!/usr/bin/env groovy
pipeline {
agent {
docker {
image 'node'
args '-u root'
}
}
stages {
stage('Build') {
steps {
echo 'Installing Dependencies...'
sh 'npm install'
}
}
stage('Run') {
steps {
echo 'Starting application...'
sh 'npm start'
}
}
stage('Test') {
steps {
echo 'Testing...'
sh 'npm test'
}
}
}
}
In the run stage, the server is started using the command node server.js, Once the server is up I want the test cases to be executed against this server. But I notice that, Jenkins never executes the Test stage since the server remains started(this is what i want), and does not exit from it.
How can I have the server started and also have the test stage run against this server?

You should run the tests before running the server. The test should not depend on the running server. Tests should require whatever is required and test, then you should run the server.
https://github.com/jenkinsci/pipeline-examples/tree/master/jenkinsfile-examples/nodejs-build-test-deploy-docker-notify

I have resolved this by creating separated build jobs and then linking them together. In the run stage, I change the directory to the build folder using "cd" command and start the server. In the test stage, I do the same, but, execute the test cases on the server started in run stage.
Thank you everyone for your inputs.

Related

Jenkins: Replace running Express-app with the most current Express-app

I have created a Jenkins-file, which first pulls the sources of a Express-app from the GitHub-Repository, then installs the dependencies, then starts the Express-App.
pipeline {
agent any
tools {
nodejs 'NodeJS'
}
stages {
stage('Build') {
steps {
sh 'npm install'
echo "install dependencies."
}
}
stage('Deploying') {
steps {
sh 'node index.js'
echo "run express-app ..."
}
}
}
}
Now I have configured "Scan Repository Triggers" to 15 minutes. So, that Jenkins runs the Jenkins-file every 15 minutes, in case there have been changes in the GitHub-repository.
The problem is, that the previous app is still running and occupying the port, which is defined in the sources.
How can I stop the older, running app and replace it with the updated app? The target is, that the respective most current version of the app is supplied, if one enters the URL.
There are multiple ways to get this done. One way is to use something like nodemon. Another clean way to manage our node server is by using something like forever. Then you can Gracefully manage the server.
forever start app.js
forever restart app.js
If you don't want to rely on additional tools. You can kill the Node server before starting it again. There are multiple ways to do this. One option is to get the process ID by the port and then kill the server. You can refer to this question.

How do launch/shutdown a Docker container before/after a mocha Test for NodeJS?

We have a NodeJS application that depends on an external database. Currently I run the mocha tests in one of two ways:
manually start a docker container, run the tests, shutdown the container
on merge using a github action (service works like a charm)
What I would like to achieve:
Being able to run my tests using npm run testsuite that starts my database container, run the mocha test and shut down the container
On investigation I found plenty of tutorials how to run tests inside a container using docker or docker-compose, but nothing how to "just" launch a temp container for the database only.
Help is very much appreciated
Encapsulate your test like so in your package.json:
{
"scripts": {
"test": "docker-compose up -d && mocha && docker-compose down"
}
}
The -d flag will allow the shell to keep processing commands after the container starts. Otherwise the docker container will indefinitely block your shell (and your tests). In case you're not using docker compose, you can always run:
docker run -d
Hopefully that helps!
I'm assuming you may be starting the test using mocha runtime with npm test -- if that's the case you may want to try starting the mocha tests by calling the API directly from a node file.
In your wrapper Node file you can try and start up the container, then start Mocha.
//start container
const mocha = new Mocha();
//more config
mocha.run( ...etc )
//shut down container

Jenkins NodeJS Plugin fails during install phase with npm ci

I'm trying to build a npm project ( Angular Project ) on the Jenkins master ( on a Docker ).
Last week I've setup the project and everything worked just fine. Today morning I've made a change on a branch and it kept failing during the first phase which include a node command called with the NodeJS plugin. There's no log on Jenkins so I can't really know what's going on.
Here's the stage code:
stages {
stage('Install') {
steps {
script {
lastRunningStage="Install"
}
nodejs(nodeJSInstallationName: 'node14.16', configId: '320662bf-2907-4c12-87f1-225abaa8d503') {
sh 'npm ci'
}
}
}

Building React App inside of Node server best practice

Have a react repo and a node repo. The are on the same root directory like so:
--myReactApp
--myNodeServer
I have a script in the React app that builds the React app and places the generated files into the Node server's public directory.
npm run-script build
#Remove the files from the server directory
rm -r ../myNodeServer/public/*
#copy over new files
cp -r ./build/. ../myNodeServer/public
This is all good, but now I am doing CI/CD with Jenkin's pipeline and it pulls the myNodeServer repo that does not have the React app in the public folder. I don't think it is best practice to include generated files in the myNodeServer's public directory, so I don't want to check in the React app into the the Node repo.
What do developer's generally do in the this situation. Is it possible to pull from 2 different repos in a pipeline script.
Right now my script looks like this:
pipeline {
agent any
tools {nodejs "Node8"}
environment {
DBPASSWORD = credentials('DBPASSWORD')
DEPLOYSECRET = credentials('DEPLOYSECRET')
}
stages {
stage('NPM Install') {
steps {
sh 'npm install'
}
}
stage('Unit Test') {
steps {
sh 'env PORT=3090 DBUSER=username DBPASSWORD=$DBPASSWORD DEPLOYSecret=$DEPLOYSECRET ENV=unitTest ./node_modules/mocha/bin/_mocha --timeout 10000 --timeout 0 --ui bdd --recursive ./test'
}
}
}
}

Using Heroku Scheduler with Node.js

There is literally no tutorial about using Heroku Scheduler with Node.js. Assume that I have a function called sayHello() and I would like to run it every 10 mins. How can I use it in controller. In ruby you write rake function_name() however no explanation made for Node. Can I write '/sayHello' or I should do extra configuration?
Create the file <project_root>/bin/say_hello:
#! /app/.heroku/node/bin/node
function sayHello() {
console.log('Hello');
}
sayHello();
process.exit();
Deploy to Heroku and test it with $ heroku run say_hello then add it to the scheduler with task name say_hello.
Explanation
Take say_hello.js as an example of a Node.js script that you would normally run using $ node say_hello.js.
Turn it into a script by
removing the .js ending
inserting the 'shebang' at the top: #! /app/bin/node [1][2]
moving it into the bin directory [3]
[1] Read about the shebang on Wikipedia.
[2] The node executable is installed in app/bin/node on Heroku. You can check it out by logging into bash on Heroku with $ heroku run bash then asking $ which node.
[3] Heroku requires scripts to be placed in the bin directory. See Defining Tasks in the Heroku Dev Center.
I agree that the Heroku documentation for scheduling tasks is not very clear for anything other than Ruby scripts. I managed to work it out after some trial and error.
A better approach is to define your schedule file called for example worker.js with following content:
function sayHello() {
console.log('Hello');
}
sayHello();
and then in the heroku schedule, you just write node worker like you define it in the Procfile and that's all!
Christophe's answer worked for me until I needed to pass a parameter to the script, at which point it failed. The issue is that node should not be specified in the task. Here is how exactly to get it working:
In your Procfile, define a process type for your script. See below for a typical Procfile with a web process and, for running "scheduled_job.js", a second process type imaginatively named "worker".
web: node app.js
worker: node scheduled_job.js
In the Heroku scheduler's Task column, just enter the name of the process type ("worker" in this example) with or without parameters. Don't enter 'node' before it. Heroku shows a dollar sign in front of it, so examples of a valid setup would be $ worker (run without arguments) or $ worker 123 abc (to execute scheduled_job.js with arguments "123" and "abc")
I am confused that nobody tried:
$ heroku run node yourScript.js
So put this in Heroku Scheduler
node yourScript.js
Worked for me.
PS: be sure to import everything your script needs.
Following steps work in my situation.
In the root folder add worker.js file.
In worker.js. Write an simple function, like above.
function sayHello() {
console.log('Hello');
}
sayHello();
Go to heroku Scheduler add-ons. Click 'add new job' and type 'worker' in the field. Then set time interval and click save.
Here are something should notice
After update works setting.If using above example, you can use heroku run node worker.js to check if it work. It should be show 'Hello' in your terminal.
I use express-babel starter for my node.js project.
Thnks so much for the previous answers here.
I found the following worked for me where feed.js is the script to run as a job on Heroku.:
<PROJECT_ROOT>/bin/feed.js
The contents of feed.js start with:
#!/usr/bin/env node
async function mediumFeed() {
await fetch('https://medium.com/feed/stokedinfluence')
And end with:
}
mediumFeed();
And on Heroku the job is defined as node bin/medium_feed.js:
To run the node js script locally feed.js you can use from the root of your project directory node bin/feed.js and to run via heroku you can use heroku run feed.js --app <APP_NAME_NOT_PIPELINE_NAME>. When using heroku command, this will run the job from the server where as running node bin/feed.js will run locally. Run locally to test and verify the code works, once deployed verify it works with the heroku run... command

Resources