Skip to content

Commit 39d5a90

Browse files
committed
- Refactor tests and models for improved clarity and functionality
- Updated test descriptions in agents, home, and login controllers to English. - Enhanced User model to include structured login records with timestamps and IP addresses. - Added method to User model for adding login records. - Improved comments for better understanding in test files.
1 parent 46e4d83 commit 39d5a90

File tree

6 files changed

+125
-51
lines changed

6 files changed

+125
-51
lines changed

nodeapp/controllers/agents.controller.test.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,40 @@ import request from "supertest";
22
import app from "../app.js";
33
import { guard, middleware } from "../lib/sessionManager";
44

5-
// Podemos mockear funciones internas
5+
//We can mock internal functions+++++++++++++++++++++++++++++++
66
jest.mock("../lib/sessionManager", () => ({
77
guard: jest.fn((req, res, next) => {
8-
// Simular que el usuario no esta autenticado
8+
// Simulate that the user is not authenticated
99
res.redirect(`/login?redir=${req.url}`);
1010

11-
// Todos los middlewares llaman a next();
11+
// All middlewares call next();
1212
next();
1313
}),
1414
middleware: jest.fn((req, res, next) => next()),
1515
useSessionInViews: jest.fn((req, res, next) => next()),
1616
}));
1717

18+
//#######################################################################################################
1819
describe("AgentsController", () => {
19-
it("Debería redirigir a la vista de login si no existe una sesión", async () => {
20+
//=========================================================================
21+
it("should redirect to the login view if no session exists", async () => {
2022
expect.assertions(2);
21-
// Hacer una request a nuestra app
23+
// Make a request to our app
2224
const response = await request(app)
23-
// en la ruta /agents/new
25+
// on the /agents/new route
2426
.get("/agents/new");
2527

26-
// Esperamos una redirección a login
28+
// We expect a redirection to login
2729
expect(response.status).toBe(302);
2830
expect(response.headers.location).toBe("/login?redir=/agents/new");
2931
});
3032

31-
it("debería llamar al guard antes de permitir el acceso a la ruta", async () => {
33+
//=========================================================================
34+
it("should call guard before allowing access to the route", async () => {
3235
expect.assertions(1);
3336
const response = await request(app).get("/agents/new");
3437

35-
// El middleware de guard se debe llamar
38+
// The guard middleware should be called
3639
expect(guard).toHaveBeenCalled();
3740
});
3841
});
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//#######################################################################################################
12
describe("homeController", () => {
2-
it.todo("debe devolver un 200 al visitar la home");
3+
//=========================================================================
4+
it.todo("should return a 200 when visiting the home page");
35
});

nodeapp/controllers/loginController.test.js

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import request from "supertest";
2-
import app from "../app";
2+
import app from "../app.js";
33
import User from "../models/User";
44

5+
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
56
jest.mock("../models/User.js");
67

7-
// Mockeamos connectMongoose para evitar conexiones reales
8+
//We mock connectMongoose to avoid real connections++++++++++++
89
jest.mock("../lib/connectMongoose.js", () => {
910
return jest.fn().mockResolvedValue({
1011
name: "mockConnection",
1112
close: jest.fn(),
1213
});
1314
});
1415

15-
// Mockeamos session para evitar problemas de sesión
16+
//We mock session to avoid session issues++++++++++++++++++++++
1617
jest.mock("express-session", () => {
1718
return () => (req, res, next) => {
1819
req.session = {
@@ -23,7 +24,7 @@ jest.mock("express-session", () => {
2324
};
2425
});
2526

26-
// Mockeamos sessionManager para simplificar los tests
27+
//We mock sessionManager to simplify the tests+++++++++++++++++
2728
jest.mock("../lib/sessionManager", () => ({
2829
middleware: (req, res, next) => {
2930
req.session = {
@@ -39,27 +40,31 @@ jest.mock("../lib/sessionManager", () => ({
3940
guard: (req, res, next) => next(),
4041
}));
4142

43+
//#######################################################################################################
4244
describe("loginController", () => {
43-
// Limpiamos mocks antes de cada test
45+
// Clear mocks before each test
4446
beforeEach(() => {
4547
jest.clearAllMocks();
4648
});
4749

48-
it("debe devolver un 200 al visitar la página de login", async () => {
50+
//=========================================================================
51+
it("should return 200 when visiting the login page", async () => {
4952
const response = await request(app).get("/login");
5053

5154
expect(response.status).toBe(200);
5255
});
5356

54-
it("debe mostrar formulario de login sin errores inicialmente", async () => {
57+
//=========================================================================
58+
it("should show login form without errors initially", async () => {
5559
const response = await request(app).get("/login");
5660

5761
expect(response.text).toContain("form");
5862
expect(response.text).not.toContain("Invalid credentials");
5963
});
6064

61-
it("debe redirigir a home tras login exitoso", async () => {
62-
// Mock de usuario existente con contraseña correcta
65+
//=========================================================================
66+
it("should redirect to home after successful login", async () => {
67+
// Mock an existing user with correct password
6368
const mockUser = {
6469
id: "user123",
6570
email: "test@example.com",
@@ -81,8 +86,9 @@ describe("loginController", () => {
8186
expect(mockUser.comparePassword).toHaveBeenCalledWith("password123");
8287
});
8388

84-
it("debe mostrar error con credenciales inválidas", async () => {
85-
// Mock de usuario existente con contraseña incorrecta
89+
//=========================================================================
90+
it("should show error with invalid credentials", async () => {
91+
// Mock an existing user with incorrect password
8692
const mockUser = {
8793
email: "test@example.com",
8894
comparePassword: jest.fn().mockResolvedValue(false),
@@ -99,8 +105,9 @@ describe("loginController", () => {
99105
expect(response.text).toContain("Invalid credentials");
100106
});
101107

102-
it("debe mostrar error cuando el usuario no existe", async () => {
103-
// Mock de usuario no existente
108+
//=========================================================================
109+
it("should show error when user does not exist", async () => {
110+
// Mock non-existent user
104111
User.findOne = jest.fn().mockResolvedValue(null);
105112

106113
const response = await request(app).post("/login").type("form").send({
@@ -112,8 +119,9 @@ describe("loginController", () => {
112119
expect(response.text).toContain("Invalid credentials");
113120
});
114121

115-
it("debe redirigir a la URL especificada después del login exitoso", async () => {
116-
// Mock de usuario existente con contraseña correcta
122+
//=========================================================================
123+
it("should redirect to specified URL after successful login", async () => {
124+
// Mock an existing user with correct password
117125
const mockUser = {
118126
id: "user123",
119127
email: "test@example.com",
@@ -132,10 +140,35 @@ describe("loginController", () => {
132140
expect(response.status).toBe(302);
133141
expect(response.headers.location).toBe("/agents/new");
134142
});
135-
it("debe cerrar sesión y redirigir a home al hacer logout", async () => {
143+
144+
//=========================================================================
145+
it("should logout and redirect to home", async () => {
136146
const response = await request(app).get("/logout");
137147

138148
expect(response.status).toBe(302);
139149
expect(response.headers.location).toBe("/");
140150
});
141151
});
152+
153+
//#######################################################################################################
154+
describe.only("TDD Exercise", () => {
155+
//=========================================================================
156+
it("should record a new login upon successful login", async () => {
157+
const mockUser = {
158+
id: "user123",
159+
email: "test@example.com",
160+
comparePassword: jest.fn().mockResolvedValue(true),
161+
addLoginRecord: jest.fn(),
162+
save: jest.fn().mockResolvedValue(true),
163+
};
164+
User.findOne = jest.fn().mockResolvedValue(mockUser);
165+
166+
await request(app).post("/login").type("form").send({
167+
email: "test@example.com",
168+
password: "password123",
169+
});
170+
171+
expect(mockUser.addLoginRecord).toHaveBeenCalled();
172+
expect(mockUser.save).toHaveBeenCalled();
173+
});
174+
});

nodeapp/models/Agent.test.js

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,26 @@ import request from "supertest";
22
import app from "../app.js";
33
import Agent from "../models/Agent.js";
44

5-
// Mockeamos el modelo Agent
5+
//We mock the Agent model++++++++++++++++++++++++++++++++++++++
66
jest.mock("../models/Agent.js");
77

8-
// Mockeamos connectMongoose para evitar conexiones reales
8+
//We mock connectMongoose to avoid real connections++++++++++++
99
jest.mock("../lib/connectMongoose.js", () => {
1010
return jest.fn().mockResolvedValue({
1111
name: "mockConnection",
1212
close: jest.fn(),
1313
});
1414
});
1515

16-
// Mockeamos session para evitar problemas de sesión
16+
//We mock session to avoid session issues++++++++++++++++++++++
1717
jest.mock("express-session", () => {
1818
return () => (req, res, next) => {
1919
req.session = { userId: null };
2020
next();
2121
};
2222
});
2323

24-
// Mockeamos sessionManager para simplificar los tests
24+
//We mock sessionManager to simplify tests+++++++++++++++++++++
2525
jest.mock("../lib/sessionManager", () => ({
2626
middleware: (req, res, next) => {
2727
req.session = { userId: null };
@@ -34,37 +34,41 @@ jest.mock("../lib/sessionManager", () => ({
3434
guard: (req, res, next) => next(),
3535
}));
3636

37+
//#######################################################################################################
3738
describe("homeController", () => {
38-
// Test de integración usando supertest
39-
describe("Pruebas de integración", () => {
40-
// Configuramos los mocks antes de cada test
39+
// Integration test using supertest
40+
//#######################################################################################################
41+
describe("Integration tests", () => {
42+
// We setup the mocks before each test
4143
beforeEach(() => {
42-
// Configuramos el mock de Agent.find para que devuelva una lista de agentes de prueba
44+
// We setup the Agent.find mock to return a list of test agents
4345
Agent.find = jest.fn().mockResolvedValue([
4446
{ _id: "agent1", name: "Smith", age: 45 },
4547
{ _id: "agent2", name: "Brown", age: 33 },
4648
]);
4749
});
4850

49-
it("debe devolver un 200 al visitar la home", async () => {
51+
//=========================================================================
52+
it("should return 200 when visiting the home page", async () => {
5053
expect.assertions(1);
5154
let response;
5255
try {
5356
response = await request(app).get("/");
5457
} catch (ex) {
55-
console.log("Error al hacer la petición");
58+
console.log("Error making the request");
5659
console.log(ex);
5760
}
5861

5962
expect(response.status).toBe(200);
60-
}, 15000); // Aumentamos el timeout a 15 segundos
63+
}, 15000); // We increase the timeout to 15 seconds
6164

62-
it("debe llamar a Agent.find con los parámetros correctos", async () => {
63-
// Realizamos la petición a la ruta /
65+
//=========================================================================
66+
it("should call Agent.find with the correct parameters", async () => {
67+
// We make the request to the / route
6468
expect.assertions(1);
6569
await request(app).get("/");
6670

67-
// Verificamos que se llamó a Agent.find
71+
// We verify that Agent.find was called
6872
expect(Agent.find).toHaveBeenCalled();
6973
});
7074
});

nodeapp/models/User.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,19 @@ const loginRecordSchema = new Schema(
1212
const userSchema = new Schema({
1313
email: { type: String, unique: true },
1414
password: String,
15-
loginRecords: [loginRecordSchema],
15+
loginRecords: [
16+
{
17+
timestamp: { type: Date, required: true, default: Date.now },
18+
ip: { type: String, required: true },
19+
},
20+
],
1621
});
1722

23+
userSchema.methods.addLoginRecord = function (ip) {
24+
this.loginRecords.push({ timestamp: new Date(), ip });
25+
this.loginRecords.sort((a, b) => a.timestamp - b.timestamp);
26+
};
27+
1828
// método del modelo
1929
userSchema.statics.hashPassword = (clearPassword) => {
2030
return bcrypt.hash(clearPassword, 7);

nodeapp/models/User.test.js

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,32 @@
1-
import User from "./User";
1+
import User from "./User.js";
22

3+
//#######################################################################################################
34
describe("User model & schema", () => {
4-
it("Debería hashear correctamente la contraseña", async () => {
5-
// Crear un password plano
5+
//=========================================================================
6+
it("Should correctly hash the password", async () => {
7+
// Create a plain password
68
const clearPassword = "supersegura";
79

8-
// Crear su hash
10+
// Create its hash
911
const hash = await User.hashPassword(clearPassword);
1012

11-
// Verificar que son diferentes
13+
// Verify that they are different
1214
expect(hash).not.toBe(clearPassword);
1315
expect(hash.length).toBeGreaterThan(1);
1416
expect(hash).not.toHaveLength(0);
1517
});
1618

17-
it.todo("Debería generar el hash utilizando la utilidad bcrypt");
19+
//=========================================================================
20+
it.todo("Should generate the hash using the bcrypt utility");
1821

19-
it("Debería comparar correctamente la contraseña", async () => {
22+
//=========================================================================
23+
it("Should correctly compare the password", async () => {
2024
expect.assertions(2);
21-
// Al crear un usuario, crear su hash y compararlo con el password plano, deberia ser true.
22-
// Crear un password plano
25+
// When creating a user, generate its hash and compare it with the plain password, it should be true.
26+
// Create a plain password
2327
const clearPassword = "supersegura";
2428

25-
// Crear su hash
29+
// Create its hash
2630
const hash = await User.hashPassword(clearPassword);
2731

2832
const user = new User({
@@ -37,3 +41,21 @@ describe("User model & schema", () => {
3741
expect(notMatchPassword).toBeFalse();
3842
});
3943
});
44+
45+
//#######################################################################################################
46+
describe.only("TDD Exercise", () => {
47+
//=========================================================================
48+
it("Should have a loginRecords field that is an array", () => {
49+
const user = new User({ email: "test@example.com", password: "hash" });
50+
expect(Array.isArray(user.loginRecords)).toBeTrue();
51+
expect(user.loginRecords).toHaveLength(0);
52+
});
53+
54+
//=========================================================================
55+
it("Each login record should have timestamp and ip", () => {
56+
const user = new User({ email: "test@example.com", password: "hash" });
57+
user.loginRecords.push({ ip: "127.0.0.1" });
58+
expect(user.loginRecords[0]).toHaveProperty("timestamp");
59+
expect(user.loginRecords[0]).toHaveProperty("ip");
60+
});
61+
});

0 commit comments

Comments
 (0)