Learn to write scalable tests and integrate them into CI/CD pipelines.
Integration tests verify how different components of your application work together, while end-to-end (E2E) tests ensure the entire system behaves as expected from the user's perspective. These tests are crucial for catching issues that unit tests might miss.
Here are some popular tools for integration and E2E testing in Node.js:
A solid testing strategy includes:
const request = require('supertest');
const app = require('../app');
describe('GET /users', () => {
it('should return a list of users with status code 200', async () => {
const response = await request(app).get('/users');
expect(response.statusCode).toBe(200);
expect(response.body).toHaveLength(5);
});
});
const { chromium } = require('playwright');
async function testLoginPage() {
const browser = await chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('http://localhost:3000/login');
await page.fill('[name="username"]', 'test@example.com');
await page.fill('[name="password"]', 'password123');
await page.click('button[type="submit"]');
// Expect successful login
const dashboardTitle = await page.title();
expect(dashboardTitle).toBe('Dashboard');
}
testLoginPage();
Integration and E2E tests should be run as part of your CI/CD pipeline to catch issues early. Tools like Jenkins, GitHub Actions, or CircleCI can automate this process.
name: Node.js Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: '16.x'
- run: npm install
- run: npm test
env:
CI: true
Welcome to the chapter on Mocking & Stubbing! In this section, we'll explore how to use ⌘jest.mock⌅, test doubles, and API mocking services to create robust and reliable tests for your Node.js applications.
Mocking involves creating fake implementations of dependencies to isolate the code being tested. This helps ensure that your tests are reliable, fast, and not dependent on external systems.
Jest provides a powerful mocking utility with ⌘jest.mock⌅. This function allows you to mock modules, functions, and APIs in your tests.
jest.mock('module-path');
const mockedFunction = jest.fn();
mockedFunction.mockImplementation(() => 'test value');
Partial mocking allows you to mock specific methods of an object while keeping others real. This is useful for testing complex interactions.
const module = require('module-path');
jest.mock('module-path');
module.methodToMock = jest.fn(() => 'mocked value');
Mocks are essential for testing in real-world applications. Common use cases include: API calls, third-party libraries, complex business logic, and UI components.
afterEach⌅ or
beforeEach⌅.Welcome to the world of Continuous Integration (CI) and Continuous Deployment (CD)! In this chapter, we'll explore how to automate your testing and deployment pipelines using GitHub Actions and Docker. By the end of this chapter, you'll be able to create robust, scalable, and efficient CI/CD pipelines for your Node.js applications.
CI/CD stands for Continuous Integration and Continuous Deployment. It's a practice where code changes are automatically verified, tested, and deployed. This ensures that your application is always in a deployable state.
GitHub Actions is a powerful platform for automating workflows directly in your GitHub repositories. It integrates seamlessly with other services and provides a simple, declarative way to define your CI/CD pipelines.
name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '16.x'
- name: npm install
run: npm install
- name: Run tests
run: npm test
Docker is essential for creating consistent deployment environments. It allows you to package your application and its dependencies into a single container that can run anywhere.
# Use an official Node.js runtime as a parent image
FROM node:16
# Set the working directory
WORKDIR /app
# Copy package files first to leverage Docker cache
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy application source code
COPY . .
# Make port 3000 available outside container
EXPOSE 3000
# Run the app when container launches
CMD ["node", "server.js"]
Let's put it all together! We'll create a GitHub Actions workflow that tests our Node.js application and deploys it using Docker.
name: Node.js CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '16.x'
cache: npm
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
- name: Build Docker image
run: docker build .
- name: Push Docker image
env:
REGISTRY_TOKEN: ${{ secrets.GITHUB_REGISTY_TOKEN }}
run: |
echo "${{ steps.build_docker.outputs.image-name }}"
CI/CD is essential for modern software development. It enables teams to deliver code faster and more reliably. For example, a Node.js application with microservices can use GitHub Actions to test each service individually before deploying them as Docker containers in production.
Question 1 of 14