Functional & E2E Testing
Functional testing (often called End-to-End or Black Box testing) doesn't care about your clean code, your design patterns, or your variable names. It only cares about one thing: "Does the feature actually work for the user?"
In the CodeHarborHub backend, this usually means sending a real HTTP request to your API and checking if you get the correct HTTP response.
The "Black Box" Concept
Imagine your API is a black box. You can't see inside it.
- You push a button (Send a
POSTrequest to/api/register). - Something happens inside.
- You check the result (Did I get a
201 Createdstatus and a Welcome email?).
Functional vs. Unit Testing
| Feature | Unit Testing | Functional Testing |
|---|---|---|
| Viewpoint | Developer (White Box) | User (Black Box) |
| Goal | Correctness of logic | Correctness of feature |
| Example | Testing the sum() function | Testing the Checkout process |
| Dependencies | Mocked (Fake) | Real (Server + DB) |
Tools for Functional Testing
To test your API endpoints without opening a browser or using Postman manually, we use Supertest. It allows us to "simulate" HTTP requests inside our Jest tests.
Example: Testing the Signup Endpoint
import request from 'supertest';
import app from '../app'; // Your Express app
import { prisma } from '../lib/prisma';
describe('POST /api/auth/signup', () => {
test('should create a new user and return 201', async () => {
// 1. Send the request
const response = await request(app)
.post('/api/auth/signup')
.send({
name: 'Ajay Dhangar',
email: 'test@codeharborhub.com',
password: 'securePassword123'
});
// 2. Assert the HTTP Status
expect(response.status).toBe(201);
// 3. Assert the Response Body
expect(response.body).toHaveProperty('id');
expect(response.body.name).toBe('Ajay Dhangar');
// 4. Verification: Is it actually in the DB?
const userInDb = await prisma.user.findUnique({
where: { email: 'test@codeharborhub.com' }
});
expect(userInDb).not.toBeNull();
});
test('should return 400 if email is missing', async () => {
const response = await request(app)
.post('/api/auth/signup')
.send({ name: 'Ajay' });
expect(response.status).toBe(400);
expect(response.body.message).toMatch(/required/);
});
});
The "Happy Path" vs. "Edge Cases"
In functional testing at CodeHarborHub, you must test both:
- The Happy Path: Everything goes perfectly (User enters correct data, server is up).
- The Sad Path: The user makes a mistake (Invalid email, password too short).
- The Edge Case: What happens if a user tries to register with an email that already exists?
Summary Checklist
- I understand that Functional Testing is "Black Box" testing.
- I know that Functional Tests check the API from the user's perspective.
- I can use Supertest to simulate HTTP requests.
- I understand the importance of testing "Sad Paths" and "Edge Cases."
Functional tests are slower than unit tests because they start the entire server and talk to the database. Run them after your unit tests have passed to catch "big picture" bugs before you deploy to production!