Skip to content
Santekno.com | Tech Tutorials and Trends
EN
📖 0%
30 Aug 2025 · 6 min read ·Article 83 / 110
Go

83. Integration Testing for Client and Server

IH
Ihsan Arif
Writer at Santekno · Backend Engineer

Integration Testing for Client and Server

In today’s digital era, modern web applications are almost always built on a distributed architecture: there is a client side (frontend) and a server side (backend), each of which is tested thoroughly and separately through unit testing. However, the “real” problems are often only discovered when these two parts interact. This is why Integration Testing—especially the kind that verifies the integration between client and server—is a crucial stage before an application is launched to users.

In this article, I will discuss integration testing for client-server applications, complete with real implementation examples, scenario simulations, and several best practices commonly used in the industry.


What Is Integration Testing Between Client and Server?

Integration Testing for client and server is the process of testing the communication and interaction between a frontend application (client) and a backend application (server). The goal is to ensure that the API contract, the data sent and received, error handling, and the user flow all work as expected. This differs from unit testing, which focuses on a single function within a limited scope.

Testing Coverage

Integration TypeExample Cases
API EndpointFetch user data, create order, login/register
Error Handling & Validation401, 422, 500 error responses, validation errors
Data Serialization/DeserializationJSON response → Object/Model on the frontend
Auth & SessionToken expired, role-based access, refresh token
Data Contract (Contract Testing)Fields, data types, JSON anatomy consistent with the docs

Integration Testing Flow: An Overview

Let’s look at an overview of the flow with the following mermaid diagram:

MERMAID
sequenceDiagram
    participant Frontend
    participant Backend
    participant MockServer

    Frontend->>Backend: Kirim request (Contoh: POST /login)
    Backend-->>Frontend: Response (success/error)

    rect rgba(0, 210, 255, 0.08)
        note over Frontend, Backend: Selama testing, Backend bisa direplace MockServer
        Frontend->>MockServer: Kirim request (POST /login)
        MockServer-->>Frontend: Response mock (simulasi)
    end

Explanation:
During integration testing, the client can be tested against the real backend or against a mock server (a simulated API). The mock approach gives you the flexibility to create positive and negative cases, as well as to isolate errors.


Case Study: A Simple Notes Application

Let’s look at a concrete example of integration testing with a JavaScript stack (React as the client and Express.js as the server).

1. Backend API Endpoint (Express.js)

js
 1// server/routes/notes.js
 2const express = require('express');
 3const router = express.Router();
 4
 5let notes = [{id: 1, text: "Halo Dunia"}];
 6
 7router.get('/notes', (req, res) => {
 8  res.json(notes);
 9});
10
11router.post('/notes', (req, res) => {
12  if (!req.body.text) return res.status(400).json({ error: "Text is required" });
13  const newNote = { id: Date.now(), text: req.body.text };
14  notes.push(newNote);
15  res.status(201).json(newNote);
16});
17
18module.exports = router;

2. Frontend Client (React, using the Fetch API)

js
 1// src/apiClient.js
 2export async function getNotes() {
 3  const response = await fetch('/api/notes');
 4  if (!response.ok) throw new Error('Failed fetch notes');
 5  return await response.json();
 6}
 7export async function addNote(text) {
 8  const response = await fetch('/api/notes', {
 9    method: 'POST',
10    headers: { 'Content-Type': 'application/json' },
11    body: JSON.stringify({ text }),
12  });
13  if (!response.ok) throw new Error('Failed add note');
14  return await response.json();
15}

Integration Testing: Tools and Methods

Here are several popular tools for performing client-server integration testing:

  • Supertest (Node.js): Tests backend API endpoints directly, without having to deploy or spin up the server over HTTP.
  • Jest + Testing Library (React): Simulates user events and validates the result of API integration on the frontend.
  • MSW (Mock Service Worker): Intercepts fetch/XHR on the client side to mock REST/GraphQL APIs.
  • Cypress / Playwright: End-to-end integration at the UI level.

Table: Comparison of Integration Testing Tools

ToolsTesting LevelMock vs Real ServerAdvantages
SupertestBackend endpointNo mock (calls the handler directly)Fast, isolates the backend
MSWFrontend API ClientCan MockSimulates various scenarios, easy to set up
CypressFullstack/E2EReal/MockReal browser, realistic scenarios

Integration Test Examples

A. Testing an API Endpoint (Backend): Supertest

js
 1// server/__tests__/notes.test.js
 2const request = require('supertest');
 3const app = require('../app');
 4
 5describe('Notes API', () => {
 6  it('GET /notes should return array of notes', async () => {
 7    const res = await request(app).get('/api/notes');
 8    expect(res.statusCode).toBe(200);
 9    expect(Array.isArray(res.body)).toBe(true);
10    expect(res.body[0]).toHaveProperty('text');
11  });
12
13  it('POST /notes with no text should return 400', async () => {
14    const res = await request(app).post('/api/notes').send({});
15    expect(res.statusCode).toBe(400);
16    expect(res.body).toHaveProperty('error');
17  });
18});

B. Testing API Client Integration on the Frontend: MSW + Testing Library

Setting Up the Mock Handler:

js
 1// src/mocks/handlers.js
 2import { rest } from 'msw';
 3
 4export const handlers = [
 5  rest.get('/api/notes', (req, res, ctx) => {
 6    return res(ctx.json([{id: 1, text: 'Catatan mock'}]));
 7  }),
 8  rest.post('/api/notes', (req, res, ctx) => {
 9    const { text } = req.body;
10    if (!text) return res(ctx.status(400), ctx.json({error: "Text is required"}));
11    return res(ctx.status(201), ctx.json({id: 2, text}));
12  })
13];

Frontend Test Simulation:

js
 1// src/__tests__/NoteApp.test.js
 2import { render, screen, fireEvent, waitFor } from '@testing-library/react';
 3import NoteApp from '../NoteApp';
 4
 5test('User dapat melihat dan menambah catatan', async () => {
 6  render(<NoteApp />);
 7  
 8  // Pastikan note mock tampil
 9  expect(screen.getByText(/Catatan mock/i)).toBeInTheDocument();
10
11  // Tambah note baru
12  fireEvent.change(screen.getByPlaceholderText(/Tulis catatan/i), {
13    target: { value: 'Catatan kedua' }
14  });
15  fireEvent.click(screen.getByText(/Tambah/i));
16  
17  await waitFor(() => 
18    expect(screen.getByText(/Catatan kedua/i)).toBeInTheDocument()
19  );
20});

Simulation: Testing Error Handling

Testing isn’t only about checking the “happy path”—it’s also about errors. Here is a simulation of an error response (for example: the server returns a 500/error field):

js
1rest.post('/api/notes', (req, res, ctx) => {
2  return res(ctx.status(500), ctx.json({ error: "Server error" }));
3});

Then, the test on the client can display an error notification, and so on.


Best Practices for Client-Server Integration Testing

  • Mocked & Real API: Start with a mocked API (for example: MSW), then move on to the real backend or a staging API for an end-to-end “smoke test”.
  • Contract Testing: Validate the data schema, for example with pact.io .
  • Pipeline Automation: Integrate the tests into CI/CD (GitHub Actions, Jenkins, etc.).
  • Data Isolation: Use a testing database (for example SQLite/mockDB) to avoid corrupting production data.

Conclusion

Integration testing between client and server is an essential foundation in modern web development. With solid integration tests, we minimize bugs in API integration, reduce regressions, and increase our confidence before the application goes to production. Use the right tools to suit your application’s needs. Happy testing!


Further Reading:


Have you already applied integration testing in your client-server project? Or do you have an interesting experience involving strange errors at the client/backend boundary? Feel free to discuss or share in the comments section! 🚀

Related Articles

💬 Comments