GitHub Actions Certification

Continuous Integration with GitHub Actions

Run and Test NodeJS App on Local Machine

In this tutorial, you'll clone, configure, and run a Node.js REST API locally before integrating it into a GitHub Actions workflow. By the end, you’ll have a working Express/Mongoose application, a full test suite, and coverage reports.

Prerequisites

Ensure you have Node.js and npm installed. On Ubuntu/Debian:

sudo apt update
sudo apt install nodejs npm

Note

Verify your installations:

node -v
npm -v

1. Clone the Repository

Fetch the source code from GitLab and navigate into the project folder:

git clone https://gitlab.com/sidd-harth/solar-system
cd solar-system

2. Install Dependencies

Install all production and development packages defined in package.json:

npm install

3. Review package.json

Open package.json to understand scripts, coverage settings, and dependencies.

Scripts Overview

ScriptDescriptionCommand
startLaunch the Express servernpm start
testRun Mocha tests with JUnit reporternpm test
coverageGenerate coverage reports (LCOV, Cobertura, text)npm run coverage

NYC Coverage Configuration

"nyc": {
  "check-coverage": true,
  "lines": 90,
  "reporter": ["text", "json-summary"]
}

Dependencies

PackagePurpose
expressWeb framework
mongooseMongoDB ODM
corsCross-Origin Resource Sharing
mocha-junit-reporterJUnit test reporting
nycCoverage tool

Dev Dependencies

PackagePurpose
mochaTest framework
chaiAssertion library
chai-httpHTTP integration testing

4. Application Entry Point (app.js)

This file initializes Express, connects to MongoDB via Mongoose, and defines your REST API endpoints.

// app.js
const express = require("express");
const bodyParser = require("body-parser");
const path = require("path");
const cors = require("cors");
const mongoose = require("mongoose");

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
}, err => {
  if (err) {
    console.error("MongoDB connection error:", err);
  } else {
    console.log("MongoDB connected");
  }
});

// Define Mongoose schemas & API routes here...

module.exports = app;

Warning

Never commit real credentials. Use environment variables or a secrets manager.


5. Test Suite (app-test.js)

Uses Mocha, Chai, and Chai HTTP to validate your API endpoints.

// app-test.js
const server = require("./app");
const chai = require("chai");
const chaiHttp = require("chai-http");

chai.should();
chai.use(chaiHttp);

describe("Planets API Suite", () => {
  describe("GET /planets/:id", () => {
    it("fetches 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();
        });
    });

    // Add more test cases as needed...
  });
});

6. Client Logic (client.js)

A simple front-end script that fetches all planets on page load:

// client.js
console.log("Initializing client.js");

window.onload = () => {
  console.log("Fetching all planets...");
  fetch("/planets")
    .then(res => {
      if (!res.ok) throw new Error("Network response was not ok");
      return res.json();
    })
    .then(data => console.log(data))
    .catch(err => console.error(err));
};

7. Dockerfile

Containerize the application for consistent deployment:

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"]

8. Kubernetes Service Manifest

Expose the application via a NodePort service:

apiVersion: v1
kind: Service
metadata:
  name: solar-system
  namespace: {_NAMESPACE_}
  labels:
    app: solar-system
spec:
  type: NodePort
  selector:
    app: solar-system
  ports:
    - protocol: TCP
      port: 3000
      targetPort: 3000

9. Running Tests Locally

9.1 Without Environment Variables

npm test

You’ll encounter:

MongooseError: The `uri` parameter to `openUri()` must be a string, got `undefined`.

9.2 Temporary Hard-Coding (Demo Only)

Replace the mongoose.connect call in app.js:

mongoose.connect("mongodb+srv://supercluster.d83jj.mongodb.net/superData", {
  user: "superuser",
  pass: "SuperPassword",
  useNewUrlParser: true,
  useUnifiedTopology: true
}, err => {
  if (err) console.error("error!!", err);
});

Then:

npm test
echo $?

Expected output:

Server successfully running on port - 3000
0

A test_results.xml file will be created for CI consumption.


10. Generating Coverage Reports

npm run coverage
echo $?

If coverage falls below the 90% threshold, you’ll see:

ERROR: Coverage for lines (88.88%) does not meet global threshold (90%)
| File   | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
|--------|---------|----------|---------|---------|-------------------|
| All    | 88.88   | 50       | 87.5    | 88.88   | 21,47-48,56       |

Coverage artifacts are saved under coverage/, including:

  • cobertura-coverage.xml
  • coverage-summary.json
  • lcov report

11. Start the Application

Run the server locally:

npm start

Visit http://localhost:3000 in your browser. Use the search bar to query planets by ID.

The image shows a webpage with a space-themed background, featuring a "Solar System" search interface and information about Earth.

Tip: Search “3” for Earth or “6” for Saturn.

The image shows a webpage about the solar system, featuring an illustration of Saturn with its rings and a description of the planet. There is a search bar labeled "Search the Planet" and a title "Solar System" at the top.


You’re now prepared to integrate this setup into your GitHub Actions workflow for CI/CD automation.

References

Watch Video

Watch video content

Previous
NodeJS Application Overview