Testing & Integration in Web Applications
Seoul National University of Science and Technology
Information Technology Management
Lecture slides index
June 4, 2025
const test = require('node:test');
const assert = require('node:assert');
const sum = (a, b) => a + b;
test.describe('Operators Test Suite', () => {
test.it('Should sum two numbers', () => {
assert.strictEqual(sum(1, 2), 3);
});
});
describe
to group related tests (e.g., for a module or function).it
to define individual test cases.assert
to check that the output matches the expected result.utils.js
) that perform several arithmetic operations: sum, multiply and divide.utils.js
sum
function is summing two numbers, the multiply
function is multiplying two numbers and the divide
function is divinding two numbers correctly.utils.js
test
and assert
.node_test
in the root directory of your project.utils.test.js
[FILE_TO_TEST].test.js
sum
, multiply
and divide
.divide
test suite)node_test/utils.test.js
const test = require('node:test');
const assert = require('node:assert');
const { sum, multiply, divide } = require('../utils');
test.describe("Utils Test Suite: sum", () => {
test.it("Should sum two numbers", () => {
assert.strictEqual(sum(1, 2), 3);
});
});
test.describe("Utils Test Suite: multiply", () => {
test.it("Should multiply two numbers", () => {
assert.strictEqual(multiply(5, 3), 15);
});
});
test.describe("Utils Test Suite: divide", () => {
test.it("Should divide two positive numbers", () => {
assert.strictEqual(divide(10, 2), 5);
});
test.it("Should divide a positive and a negative number", () => {
assert.strictEqual(divide(-10, 2), -5);
});
test.it("Should return Infinity when dividing by 0", () => {
assert.strictEqual(divide(10, 0), Infinity);
});
test.it("Should return NaN when dividing 0 by 0", () => {
assert.ok(Number.isNaN(divide(0, 0)));
});
});
package.json
in the scripts
property.{
"name": "unit_testing",
"version": "1.0.0",
"main": "app.js",
"scripts": {
"node-test": "node --test \"node_test/*.test.js\""
},
"author": "jobregon",
"license": "MIT",
"description": ""
}
**/*.test.{cjs,mjs,js}
**/*-test.{cjs,mjs,js}
**/*_test.{cjs,mjs,js}
npm run node-test
jest.confg.js
to specify that we should ignore the node_test
folder (this is not necessary if you are only using Jest as a test library)package.json
file:utils.js
using Jestexpect()
is used to wrap the actual value you want to test..toBe()
checks that the actual value is exactly equal (using ===) to the expected value.toBeNull()
, toThrow()
, (more in this link)describe
and it
functions, so we don’t need to import them.jest_test/utils.test.js
const { sum, multiply, divide } = require('../utils.js');
describe("Utils Test Suite: sum", () => {
test("Should sum two numbers", () => {
expect(sum(1, 2)).toBe(3);
});
});
describe("Utils Test Suite: multiply", () => {
test("Should multiply two numbers", () => {
expect(multiply(5, 3)).toBe(15);
});
});
describe("Utils Test Suite: divide", () => {
test("Should divide two positive numbers", () => {
expect(divide(10, 2)).toBe(5);
});
test("Should divide a positive and a negative number", () => {
expect(divide(-10, 2)).toBe(-5);
});
test("Should return Infinity when dividing by 0", () => {
expect(divide(10, 0)).toBe(Infinity);
});
test("Should return NaN when dividing 0 by 0", () => {
expect(Number.isNaN(divide(0, 0))).toBe(true);
});
});
npm run jest-test
package.json
:{
"scripts": {
"node-test": "node --test \"node_test/*.test.js\"",
"jest-test": "jest",
"jest-test:coverage": "jest --coverage",
"node-test:coverage": "node --test --experimental-test-coverage \"node_test/*.test.js\""
}
}
--experimental-test-coverage
flag to enable this featuresubstract
, to our utils.js
file:npm run node-test:coverage
and npm run jest-test:coverage
subtract
function.Node.js
Jest
index.html
file located in coverage/lcov-report
in our browser to see the results.utils.js
GET /api/flights/:id
app.get(
'/api/flights/:id',
async (req, res) => {
try {
const flightId = parseInt(req.params.id);
// 1) Flight info
const flight = await getFlight(flightId);
// check if flight exists
if (!flight) {
res.sendStatus(404);
} else {
// 2) Assigned passengers (persons)
const passengers = await getPassengers(flightId);
res.json({
id: flight.id,
origin: flight.origin,
destination: flight.destination,
duration: flight.duration,
passengers: passengers
});
}
} catch (err) {
res.status(500).json({ message: err.message });
}
}
);
const request = require('supertest');
const app = require('../app'); // your Express app
test('GET /api/flights returns 200', async () => {
const res = await request(app).get('/api/flights');
expect(res.statusCode).toBe(200);
});
Important
Do not forget to install Jest in the airline project and add the test scripts to package.json
as we learned before.
.listen()
app.js
to export the app:const express = require('express');
const app = express();
// routes go here...
module.exports = app;
server.js
app
and separate app.listen()
into its own file (e.g.,server.js
) because:
jest.mock()
allows os to mock modules by erasing the actual implementation of functions and capturing calls to the functions in the modulemockResolvedValue
for .getFlight
that returns the data we want to use in our tests.it.todo
function marks the tests that we need to add.
tests/flight.test.js
const request = require('supertest');
const app = require('../app');
// Mock your database functions
jest.mock('../db');
const { getFlight, getPassengers } = require('../db');
describe('GET /api/flights/:id', () => {
it('should return 404 if flight not found', async () => {
getFlight.mockResolvedValue(null); // simulate no flight found
const res = await request(app).get('/api/flights/999');
expect(res.statusCode).toBe(404);
});
it('should return flight with passengers', async () => {
getFlight.mockResolvedValue({
id: 1,
origin: 'Seoul',
destination: 'Tokyo',
duration: 120
});
getPassengers.mockResolvedValue([
{ id: 1, first: 'Alice', last: 'Kim' },
{ id: 2, first: 'Bob', last: 'Lee' }
]);
const res = await request(app).get('/api/flights/1');
expect(res.statusCode).toBe(200);
expect(res.body).toEqual({
id: 1,
origin: 'Seoul',
destination: 'Tokyo',
duration: 120,
passengers: [
{ id: 1, first: 'Alice', last: 'Kim' },
{ id: 2, first: 'Bob', last: 'Lee' }
]
});
});
it('should return 500 on error', async () => {
getFlight.mockImplementation(() => {
throw new Error('DB failed');
});
const res = await request(app).get('/api/flights/1');
expect(res.statusCode).toBe(500);
expect(res.body).toHaveProperty('message', 'DB failed');
});
});
describe("GET /api/flights", () => {
it.todo("Should return an empty array when there's no flights data")
it.todo("Should return all the flights")
})
npm run jest-test:coverage
/api/flights/
)app.js
has 50% of coverage (app.use
functions were not tested)db.js
has 0% of coverage
GitHub Actions
npm ci
is similar to npm install
, except it’s meant to be used in automated environments.github/workflows/node.js.yml
name: Node.js CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22.x'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm jest-test
Docker
Web Programming