GitHub Actions
Continuous Integration with GitHub Actions
Run and Test NodeJS App on Local Machine
In this guide, you’ll clone a Node.js application, install dependencies, run tests with coverage enforcement, and start the server locally. These steps form the foundation for automating your CI/CD pipeline with GitHub Actions.
Prerequisites
Make sure you have the following installed:
- Node.js (v14+)
- npm (bundled with Node.js)
On Debian/Ubuntu, you can install them with:
sudo apt update
sudo apt install nodejs npm
Clone the Repository
Fetch the project source and switch into its directory:
git clone https://gitlab.com/sidd-harth/solar-system.git
cd solar-system
Project Structure
File/Folder | Description |
---|---|
package.json | Project metadata, dependencies & npm scripts |
app.js | Express server logic and MongoDB connection |
app-test.js | Mocha & Chai test suite |
index.html | Simple frontend HTML |
client.js | Frontend JavaScript controller |
Dockerfile | Instructions to build a Docker image |
k8s/ | Kubernetes manifest files |
package.json
Your package.json
defines scripts, dependencies, and code coverage settings:
{
"name": "Solar System",
"version": "6.7.6",
"author": "Siddharth Barahalikar <[email protected]>",
"license": "MIT",
"scripts": {
"start": "node app.js",
"test": "mocha app-test.js --timeout 10000 --reporter mocha-junit-reporter --exit",
"coverage": "nyc --reporter cobertura --reporter lcov --reporter text --reporter json-summary mocha app-test"
},
"nyc": {
"check-coverage": true,
"lines": 90
},
"dependencies": {
"cors": "2.8.5",
"express": "^4.18.2",
"mongoose": "^6.0.0"
},
"devDependencies": {
"chai": "^4.3.6",
"chai-http": "^4.3.0",
"mocha": "^10.0.0",
"mocha-junit-reporter": "^2.0.0",
"nyc": "^15.0.0"
}
}
Available npm Scripts
Script | Command | Description |
---|---|---|
start | npm start | Launches the Express server |
test | npm test | Runs Mocha tests with JUnit reporting |
coverage | npm run coverage | Generates code coverage reports using nyc |
Application Code (app.js)
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const mongoose = require("mongoose");
const path = require("path");
const app = express();
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, "/")));
app.use(cors());
mongoose.connect(
process.env.MONGO_URI,
{
user: process.env.MONGO_USERNAME,
pass: process.env.MONGO_PASSWORD,
useNewUrlParser: true,
useUnifiedTopology: true,
},
function(err) {
if (err) {
console.log("error!! " + err);
} else {
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server successfully running on port - ${PORT}`);
});
}
}
);
// Define your REST API endpoints here
// e.g., app.get("/planets/:id", ...)
module.exports = app;
Test Suite (app-test.js)
const mongoose = require("mongoose");
const server = require("./app");
const chai = require("chai");
const chaiHttp = require("chai-http");
chai.should();
chai.use(chaiHttp);
describe('Planets API Suite', () => {
describe('Fetching Planet Details', () => {
it('should fetch a planet named Mercury', (done) => {
chai.request(server)
.get('/planets/1')
.end((err, res) => {
res.should.have.status(200);
res.body.name.should.equal('Mercury');
done();
});
});
// Additional tests for Venus, Earth, etc.
});
});
Frontend Controller (client.js)
console.log('We are inside client.js');
/* on page Load */
window.onload = function() {
const planet_id = document.getElementById('planetID').value;
console.log('onLoad - Request Planet ID - ' + planet_id);
fetch("/planets")
.then((res) => {
if (res.ok) return res.json();
throw new Error('Request failed');
})
.then((data) => {
// Populate HTML with planet data
})
.catch((error) => {
console.error(error);
});
};
Dockerfile
FROM node:18-alpine3.17
WORKDIR /usr/app
COPY package*.json ./
RUN npm install
COPY . .
ENV MONGO_URI=uriPlaceholder
ENV MONGO_USERNAME=usernamePlaceholder
ENV MONGO_PASSWORD=passwordPlaceholder
EXPOSE 3000
CMD [ "npm", "start" ]
Kubernetes Service Manifest
apiVersion: v1
kind: Service
metadata:
name: solar-system
namespace: {_NAMESPACE_}
labels:
app: solar-system
spec:
type: NodePort
selector:
app: solar-system
ports:
- port: 3000
targetPort: 3000
protocol: TCP
Install Dependencies
Install all Node.js dependencies:
npm install
This creates the node_modules/ directory.
Run Tests
Your tests require MongoDB credentials set via environment variables:
npm test
If credentials are not provided, you may see an error like:
MongooseError: The `uri` parameter to `openUri()` must be a string, got "undefined".
Warning
Be sure to export MONGO_URI
, MONGO_USERNAME
, and MONGO_PASSWORD
before running tests.
Hard-code Credentials (for Demo)
If you want to bypass environment variables during a demo, update app.js:
mongoose.connect(
'mongodb+srv://supercluster.d83jj.mongodb.net/superData',
{
user: 'superuser',
pass: 'SuperPassword',
useNewUrlParser: true,
useUnifiedTopology: true,
},
function(err) { … }
);
Then re-run:
npm test
Expected output indicating the server started and tests passed:
> Solar [email protected] test
> mocha app-test.js --timeout 10000 --reporter mocha-junit-reporter --exit
Server successfully running on port - 3000
Verify exit code:
echo $?
# 0
A test_results.xml file is generated for CI.
Run Coverage
Generate coverage reports with:
npm run coverage
Sample failure output if coverage is below threshold:
ERROR: Coverage for lines (88.88%) does not meet global threshold (90%)
Verify exit code:
echo $?
# 1
Reports are available in the coverage/ directory (cobertura XML, lcov, JSON summary).
Start the Application
Launch your server locally:
npm start
By default, the server listens on port 3000. Open your browser at:
http://localhost:3000
Use the search bar to look up planet details by ID. Data is served from a MongoDB Atlas cluster and displayed in the UI.
Links and References
Watch Video
Watch video content