When working on a full-stack project that combines Node.js and React, managing continuous integration and deployment (CI/CD) can become a significant pain point. You might find yourself stuck in a situation where changes to your backend API aren’t reflected in your frontend application, or automated testing is failing without clear error messages. This can lead to wasted time debugging and re-deploying the entire application.
You’ll build a robust CI/CD pipeline using GitHub Actions that automates testing and deployment for both your Node.js backend and React frontend. By the end of this tutorial, you’ll have configured GitHub Actions to run unit tests on your backend API using Jest and Supertest, as well as implement automated deployment to Vercel with a single click.
Setting Up a New Node.js Project with Express and React
To start our journey, let’s create a new Node.js project using Express as the backend framework and React for the frontend.
First, open your terminal and run:
npm init -y
This will create a package.json file in the root of your project. Next, install Express and React using npm:
npm install express react react-dom
Create a new directory called src to hold our frontend code:
mkdir src
Navigate into the src directory and create an index.js file to hold our React app:
cd src && touch index.js
Add some basic Express routing in app.js (create this file in the root of your project):
// app.js
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('<h1>Hello World</h1>');
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
Create an index.html file in the public directory to serve our React app:
<!-- public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script src="/index.js"></script>
</body>
</html>
Now you can start the server using npm:
node app.js
Visit http://localhost:3000 in your web browser to see “Hello World” displayed. This concludes our setup for this section. We now have a basic Node.js project with Express and React ready for further development. Next, we’ll create a GitHub repository and initialize Git flow.
Creating a GitHub Repository and Initializing Git Flow
First, navigate to GitHub and sign in with your account credentials. Click on the “+” button in the top-right corner to create a new repository.
echo "# my-node-react-app" >> README.md
git add README.md
git commit -m "initial commit"
Name your repository my-node-react-app (feel free to use any name you like). In this example, we’ve initialized the project with an initial commit containing a basic README.md file.
Next, create a new branch using Git Flow. This will allow us to work on our feature in isolation and keep our codebase clean. I’ll be working on a feature called “login-feature” for demonstration purposes.
git checkout -b login-feature
The login-feature branch is now active. Create a .gitignore file to exclude files that shouldn’t be committed, like node_modules.
// .gitignore
node_modules/
.env
Initialize Git Flow by running the following command:
git flow init -feature Branch=feature/login-feature
This will create necessary branches for your feature branch. Set up a .env file to store environment variables.
# .env.example
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=myuser
DB_PASSWORD=mypassword
Create a local copy of this file using:
cp .env.example .env
I’ve now initialized the project’s Git flow. In the next step, we’ll configure GitHub Actions for automated testing and deployment.
Configuring GitHub Actions for Automated Testing and Deployment
In this step, we’ll configure GitHub Actions to automate testing and deployment of our Node.js and React application.
First, navigate to your repository’s settings in GitHub and select “Actions” from the left-hand menu. Click on “New workflow” and choose “Set up a workflow yourself”.
Create a new file called .github/workflows/ci-cd.yml with the following code:
name: CI/CD
on:
push:
branches:
- main
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install dependencies
run: |
npm install
- name: Build and test frontend
run: |
npm run build
npm run test
- name: Deploy to Vercel
uses: vercel/action-deploy@v1
This workflow will trigger automatically whenever a push is made to the main branch. It installs dependencies, builds and tests the frontend, and then deploys the application to Vercel.
Make sure to replace vercel/action-deploy@v1 with your actual Vercel API key (found in the Vercel dashboard).
Now that we have our workflow set up, let’s go ahead and push some changes to see it in action.
Writing Unit Tests for the Backend API using Jest and Supertest
Now that our backend API is set up with Express.js, it’s essential to write unit tests to ensure it works as expected. We’ll use Jest as our testing framework and Supertest to make HTTP requests to our API.
First, install the required packages in your project directory:
npm install --save-dev jest supertest
Next, create a new file tests/Unit/api.php with the following code:
namespace App\Tests\Unit\Api;
use PHPUnit\Framework\TestCase;
use Supergiant\Supertest\LaravelTestCase as SupertestTestCase;
class ApiControllerTest extends TestCase
{
use SupertestTestCase;
public function testGetUsers()
{
$response = $this->get('/api/users');
$this->assertEquals(200, $response->getStatusCode());
$this->assertJson($response->getBody()->getContents());
}
// Add more tests for other API endpoints as needed
}
In this example, we’re using Supertest to make a GET request to the /api/users endpoint and asserting that it returns a 200 status code with JSON response.
To run these unit tests, create a new file tests/Unit/api.test.php with the following code:
namespace App\Tests\Unit\Api;
use PHPUnit\Framework\TestCase;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Laravel\Sanctum\Testing\MakeRequestable;
class ApiControllerTest extends TestCase
{
use MakeRequestable, WithFaker;
protected function setUp(): void
{
parent::setUp();
// Set up test database and seed data as needed
}
public function testGetUsers()
{
$response = $this->get('/api/users');
// Asserts go here
}
}
Run the tests using phpunit or your preferred testing tool to catch any issues with your backend API. With these unit tests in place, you can be confident that your API is working correctly and make changes without worrying about breaking it.
This concludes our section on writing unit tests for the backend API using Jest and Supertest.
Implementing Continuous Integration and Deployment (CI/CD) Pipeline
Now that we have our GitHub Actions setup for automated testing and deployment, it’s time to implement a CI/CD pipeline. This pipeline will automate the process of building, testing, and deploying our application on every push to the main branch.
First, create a new file in your repository’s .github/workflows directory called ci-cd.yml. This file will define the steps for our CI/CD pipeline.
name: Continuous Integration and Deployment
on:
push:
branches:
- main
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install dependencies
run: |
npm install
- name: Run tests
run: |
npm test
- name: Build and deploy
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
run: |
npm run build
vercel deploy --token $VERCEL_TOKEN
This pipeline uses the actions/checkout action to checkout our code, installs dependencies with npm install, runs tests using npm test, and finally builds and deploys our application using Vercel.
Make sure to replace ${{ secrets.VERCEL_TOKEN }} with your actual Vercel token.
With this CI/CD pipeline in place, every push to the main branch will trigger a build, test, and deployment of our application on Vercel. This ensures that our application is always up-to-date and running smoothly.
Deploying the Application to a Production Environment on Vercel
Now that our application is complete and we have a Continuous Integration and Deployment (CI/CD) pipeline set up in GitHub Actions, it’s time to deploy it to a production environment.
First, let’s create a new account on Vercel if you haven’t already. Then, navigate to your repository settings on GitHub and click on “Actions” > “General” > “Secrets”. Add the following secrets:
VERCEL_PROJECT_ID: <your-project-id>
VERCEL_TOKEN: <your-vercel-token>
Next, in your vercel.json file (create it if you don’t have one), add the following configuration:
{
"version": 2,
"builds": [
{
"src": "package*.json",
"use": "@vercel/static-build"
}
],
"routes": [
{
"src": "/api/(.*)",
"dest": "/index.php/api/$1"
},
{
"src": "/(.*)",
"dest": "/"
}
]
}
Make sure to replace /index.php with the correct path to your PHP entry point. Finally, create a new GitHub Actions workflow file named .github/workflows/vercel.yml:
name: Deploy to Vercel
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Login to Vercel
uses: vercel/login@v1
- name: Deploy to Vercel
uses: vercel/deploy@v1
with:
project-id: ${{ secrets.VERCEL_PROJECT_ID }}
token: ${{ secrets.VERCEL_TOKEN }}
This will automatically deploy your application to Vercel when you push changes to the main branch.
That’s it! Your application should now be live on Vercel, and any changes pushed to GitHub will trigger a redeployment. With this setup in place, you can focus on writing new code without worrying about infrastructure management.
Monitoring and Troubleshooting with GitHub Actions and New Relic
Now that our application is live on Vercel, we need to monitor its performance and troubleshoot issues as they arise. In this section, we’ll integrate GitHub Actions with New Relic to get real-time monitoring and alerting capabilities.
First, let’s create a new file in the .github/workflows directory called new-relic.yml. This file will contain the necessary configuration for our workflow:
name: Monitor Application
on:
push:
branches:
- main
jobs:
monitor:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install New Relic
run: |
npm install newrelic
- name: Configure New Relic
env:
NEW_RELIC_API_KEY: ${{ secrets.NEW_RELIC_API_KEY }}
NEW_RELIC_LICENSE_KEY: ${{ secrets.NEW_RELIC_LICENSE_KEY }}
run: |
npx newrelic config set api_key ${NEW_RELIC_API_KEY} license_key ${NEW_RELIC_LICENSE_KEY}
- name: Monitor application
env:
NEW_RELIC_AGENT_ID: ${env.NEW_RELIC_AGENT_ID}
run: |
npx newrelic monitor start --agent-id ${NEW_RELIC_AGENT_ID}
In the above code, we’re using the actions/checkout action to check out our code, then installing and configuring New Relic. Finally, we use the newrelic command to start monitoring our application.
We need to add two secrets to our GitHub repository: NEW_RELIC_API_KEY and NEW_RELIC_LICENSE_KEY. These can be obtained from your New Relic account.
With this workflow in place, we’ll get real-time monitoring and alerting capabilities for our application. This will help us catch performance issues early on and ensure that our application remains healthy and stable.
Frequently Asked Questions
How do I set up GitHub Actions for my Node.js and React project?
To set up GitHub Actions, create a new file in the .github/workflows directory of your repository and define the workflow using YAML. This will allow you to automate testing and deployment for both your backend API and frontend application.
Why am I getting errors when running unit tests with Jest and Supertest?
Common issues include incorrect test setup, mismatched dependencies, or forgotten imports. Ensure that you have properly set up your test environment and checked the error messages for clues on what’s going wrong.
Can I use a different CI/CD tool instead of GitHub Actions?
Yes, there are other options available such as Travis CI or CircleCI. However, GitHub Actions provides seamless integration with GitHub repositories and is often the preferred choice for many developers.
How do I deploy my React application to Vercel using GitHub Actions?
To deploy your React app to Vercel, create a new workflow in your repository that triggers on push events. Use the vercel npm package to automate deployment and configure the workflow to use Vercel’s API.
