diff --git a/tests/unit/authMiddleware.auth.test.js b/tests/unit/authMiddleware.auth.test.js index 60e457a..028d528 100644 --- a/tests/unit/authMiddleware.auth.test.js +++ b/tests/unit/authMiddleware.auth.test.js @@ -12,18 +12,25 @@ import jwt from 'jsonwebtoken'; import { authenticate, optionalAuth } from '../../middleware/auth.js'; import { createMockReq, createMockRes } from '../helpers/mockUtils.js'; +/** + * Test suite for JWT token authentication middleware. + * Tests token presence, format, validity, and expiration handling. + */ describe('Auth Middleware - Token Handling', () => { const originalEnv = process.env.JWT_SECRET; + // Set up test JWT secret for token generation beforeAll(() => { process.env.JWT_SECRET = 'test-secret-key-for-testing'; }); + // Restore original JWT secret after tests afterAll(() => { process.env.JWT_SECRET = originalEnv; }); + // Tests for required authentication middleware (blocks unauthenticated) describe('authenticate', () => { it('should return 401 when no authorization header', () => { const req = createMockReq(); diff --git a/tests/unit/authMiddleware.roles.test.js b/tests/unit/authMiddleware.roles.test.js index 6b25c59..7fb13c2 100644 --- a/tests/unit/authMiddleware.roles.test.js +++ b/tests/unit/authMiddleware.roles.test.js @@ -11,19 +11,28 @@ import { userAuth, adminAuth } from '../../middleware/auth.js'; import { USER_ROLES } from '../../config/constants.js'; import { createMockReq, createMockRes } from '../helpers/mockUtils.js'; +/** + * Test suite for role-based access control middleware. + * Tests userAuth (resource ownership) and adminAuth (admin-only access). + */ describe('Auth Middleware - Role-Based Access', () => { const originalEnv = process.env.JWT_SECRET; + // Set up test JWT secret for token generation beforeAll(() => { process.env.JWT_SECRET = 'test-secret-key-for-testing'; }); + // Restore original JWT secret after tests afterAll(() => { process.env.JWT_SECRET = originalEnv; }); + // Tests for user authorization middleware (resource ownership checks) + // Tests for user authorization: verifies owner access, denies others describe('userAuth', () => { + // User accessing their own resource should be allowed it('should allow access when user ID matches authenticated user', () => { const validToken = jwt.sign( { userId: 123, username: 'testuser' }, @@ -134,7 +143,9 @@ describe('Auth Middleware - Role-Based Access', () => { }); }); + // Tests for admin authorization: only ADMIN role gets access describe('adminAuth', () => { + // Admin token with ADMIN role should pass it('should allow access for admin users', () => { const adminToken = jwt.sign( { userId: 1, username: 'admin', role: USER_ROLES.ADMIN }, diff --git a/tests/unit/favouriteService.test.js b/tests/unit/favouriteService.test.js index f0fe123..0ce6faf 100644 --- a/tests/unit/favouriteService.test.js +++ b/tests/unit/favouriteService.test.js @@ -13,10 +13,15 @@ import * as favouriteService from '../../services/favouriteService.js'; import db from '../../config/db.js'; import { ValidationError, NotFoundError } from '../../utils/errors.js'; +/** + * Test suite for favourite and disliked places service. + * Tests add, get, and remove operations for both favourites and dislikes. + */ describe('Favourite Service', () => { let testUserId; let testPlaceId; + // Create test user and place before each test beforeEach(async () => { // Create test user and place const user = await db.createUser({ diff --git a/tests/unit/helpers.test.js b/tests/unit/helpers.test.js index cd568d2..883f071 100644 --- a/tests/unit/helpers.test.js +++ b/tests/unit/helpers.test.js @@ -20,8 +20,10 @@ import { */ describe('Helpers - Core Functions', () => { + // Tests for Haversine distance calculation between coordinates describe('calculateDistance()', () => { + // Validates accurate distance calculations between known points describe('Happy Path - Valid Distance Calculations', () => { it('should calculate correctly the distance between two points', () => { @@ -59,8 +61,10 @@ describe('Helpers - Core Functions', () => { }); + // Tests for user object sanitization (password removal) describe('sanitizeUser()', () => { + // Verifies password field is removed from user objects describe('Happy Path - Remove Password', () => { it('should remove the password field from user object', () => { @@ -123,8 +127,9 @@ describe('Helpers - Core Functions', () => { }); + // Tests for batch user sanitization describe('sanitizeUsers()', () => { - + // Should remove password from all users in array it('should sanitize array of users', () => { const users = [ { userId: 1, username: 'user1', password: 'pass1' }, @@ -145,8 +150,9 @@ describe('Helpers - Core Functions', () => { }); + // Tests for pagination query parameter parsing describe('parsePagination()', () => { - + // Validates page and pageSize extraction from query it('should parse pagination parameters', () => { const result = parsePagination({ page: '2', pageSize: '10' }); expect(result).toEqual({ page: 2, pageSize: 10, skip: 10 }); diff --git a/tests/unit/mongoDb.data.test.js b/tests/unit/mongoDb.data.test.js index 6c537ca..56f8eb1 100644 --- a/tests/unit/mongoDb.data.test.js +++ b/tests/unit/mongoDb.data.test.js @@ -1,6 +1,9 @@ /** * @fileoverview MongoDB Unit Tests - Data Operations * @module tests/unit/mongoDb.data.test + * + * Tests MongoDB data layer operations including reviews and favourites. + * Uses in-memory MongoDB for isolated testing without external dependencies. */ import mongoDb from '../../config/mongoDb.js'; @@ -11,20 +14,28 @@ import { clearMongoDbData } from '../helpers/mongoDbSetup.js'; +/** + * Test suite for MongoDB data operations. + * Covers review CRUD and favourite place management. + */ describe('MongoDB Data Operations', () => { + // Initialize in-memory MongoDB before tests beforeAll(async () => { await setupMongoDb(); }); + // Clean up MongoDB connection after tests afterAll(async () => { await teardownMongoDb(); }); + // Reset data state before each test for isolation beforeEach(async () => { await clearMongoDbData(); }); + // Tests for adding and retrieving place reviews describe('Review Operations', () => { let testUser; let testPlace; diff --git a/tests/unit/mongoDb.user.test.js b/tests/unit/mongoDb.user.test.js index 9cd5c17..50f6dc2 100644 --- a/tests/unit/mongoDb.user.test.js +++ b/tests/unit/mongoDb.user.test.js @@ -1,6 +1,9 @@ /** * @fileoverview MongoDB Unit Tests - User Operations * @module tests/unit/mongoDb.user.test + * + * Tests MongoDB user data layer: user creation, email lookup, and settings. + * Uses in-memory MongoDB for fast, isolated test execution. */ import mongoDb from '../../config/mongoDb.js'; @@ -10,6 +13,10 @@ import { clearMongoDbData } from '../helpers/mongoDbSetup.js'; +/** + * Test suite for MongoDB user operations. + * Covers createUser, findUserByEmail, and user settings management. + */ describe('MongoDB User Operations', () => { beforeAll(async () => { await setupMongoDb(); diff --git a/tests/unit/placeService.test.js b/tests/unit/placeService.test.js index 09dcc2b..90495a0 100644 --- a/tests/unit/placeService.test.js +++ b/tests/unit/placeService.test.js @@ -13,7 +13,12 @@ import * as placeService from '../../services/placeService.js'; import db from '../../config/db.js'; import { ValidationError, NotFoundError } from '../../utils/errors.js'; +/** + * Test suite for place service business logic. + * Tests CRUD operations and search functionality for places. + */ describe('Place Service', () => { + // Tests for place creation with full and minimal data describe('createPlace', () => { it('should create a new place successfully', async () => { const placeData = { diff --git a/tests/unit/preferenceController.test.js b/tests/unit/preferenceController.test.js index 7dd5a7c..118ca4e 100644 --- a/tests/unit/preferenceController.test.js +++ b/tests/unit/preferenceController.test.js @@ -28,14 +28,19 @@ jest.unstable_mockModule('../../config/db.js', () => ({ } })); -// Import controller after mocking +// Import controller after mocking to ensure mocks are in place const preferenceController = (await import('../../controllers/preferenceController.js')).default; +/** + * Test suite for preference controller error handling paths. + * Verifies that database errors are properly passed to next() middleware. + */ describe('Preference Controller - Error Handling', () => { let mockReq; let mockRes; let mockNext; + // Reset mocks and create fresh request/response objects beforeEach(() => { jest.clearAllMocks(); diff --git a/tests/unit/preferenceService.crud.test.js b/tests/unit/preferenceService.crud.test.js index 1b1b606..eead493 100644 --- a/tests/unit/preferenceService.crud.test.js +++ b/tests/unit/preferenceService.crud.test.js @@ -1,15 +1,23 @@ /** * @fileoverview Unit Tests for Preference Service - CRUD Operations * @module tests/unit/preferenceService.crud.test + * + * Tests preference profile CRUD: create, read, update operations. + * Validates ID formats in input and proper NotFoundError handling. */ import * as preferenceService from '../../services/preferenceService.js'; import db from '../../config/db.js'; import { ValidationError, NotFoundError } from '../../utils/errors.js'; +/** + * Test suite for preference profile CRUD operations. + * Tests createPreferenceProfile, getPreferenceProfiles, getPreferenceProfile. + */ describe('Preference Service - CRUD Operations', () => { let testUserId; + // Create test user to own the preference profiles beforeEach(async () => { const user = await db.createUser({ username: 'prefuser', diff --git a/tests/unit/preferenceService.mutations.test.js b/tests/unit/preferenceService.mutations.test.js index 3707edd..5cdeb15 100644 --- a/tests/unit/preferenceService.mutations.test.js +++ b/tests/unit/preferenceService.mutations.test.js @@ -1,15 +1,23 @@ /** * @fileoverview Unit Tests for Preference Service - Mutations * @module tests/unit/preferenceService.mutations.test + * + * Tests preference profile mutation operations: update and delete. + * Validates ID formats in input and proper NotFoundError handling. */ import * as preferenceService from '../../services/preferenceService.js'; import db from '../../config/db.js'; import { ValidationError, NotFoundError } from '../../utils/errors.js'; +/** + * Test suite for preference profile mutation operations. + * Tests updatePreferenceProfile and deletePreferenceProfile functions. + */ describe('Preference Service - Mutations', () => { let testUserId; + // Create test user to own the preference profiles beforeEach(async () => { const user = await db.createUser({ username: 'prefuser', diff --git a/tests/unit/responses.error.test.js b/tests/unit/responses.error.test.js index 9c5bd93..fb4831e 100644 --- a/tests/unit/responses.error.test.js +++ b/tests/unit/responses.error.test.js @@ -1,6 +1,9 @@ /** * @fileoverview Response Utilities Tests - Error Responses * @module tests/unit/responses.error.test + * + * Tests standardized error response functions for HTTP responses. + * Verifies correct status codes, error types, and message formatting. */ import { @@ -14,10 +17,17 @@ import { import { createMockRes } from '../helpers/mockUtils.js'; +/** + * Test suite for error response utility functions. + * Tests sendError, sendValidationError, sendAuthError, sendForbiddenError, + * sendNotFoundError, and sendConflictError functions. + */ describe('Response Utilities - Error Responses', () => { + // Tests for the generic sendError function with status codes and details describe('sendError()', () => { + // Validates correct error response structure and status codes describe('Happy Path - Error Responses', () => { it('should return error with status code', () => { diff --git a/tests/unit/responses.success.test.js b/tests/unit/responses.success.test.js index 56c5c6d..bc4f032 100644 --- a/tests/unit/responses.success.test.js +++ b/tests/unit/responses.success.test.js @@ -1,6 +1,9 @@ /** * @fileoverview Response Utilities Tests - Success Responses * @module tests/unit/responses.success.test + * + * Tests standardized success response functions for HTTP responses. + * Verifies status codes, data structure, and pagination metadata. */ import { @@ -11,11 +14,16 @@ import { } from '../../utils/responses.js'; import { createMockRes } from '../helpers/mockUtils.js'; - +/** + * Test suite for success response utility functions. + * Tests sendSuccess, sendCreated, sendNoContent, sendPaginatedResponse. + */ describe('Response Utilities - Success Responses', () => { + // Tests for generic success response with data and optional meta describe('sendSuccess()', () => { + // Validates correct response structure and status codes describe('Happy Path - Success Responses', () => { it('should return 200 with data', () => { diff --git a/tests/unit/userController.test.js b/tests/unit/userController.test.js index c54a6fc..54640b7 100644 --- a/tests/unit/userController.test.js +++ b/tests/unit/userController.test.js @@ -26,14 +26,19 @@ jest.unstable_mockModule('../../services/userService.js', () => ({ } })); -// Import controller after mocking +// Import controller after mocking to ensure mocks are in place const userController = (await import('../../controllers/userController.js')).default; +/** + * Test suite for user controller error handling paths. + * Verifies that service errors are properly passed to next() middleware. + */ describe('User Controller - Error Handling', () => { let mockReq; let mockRes; let mockNext; + // Reset mocks and create fresh request/response objects beforeEach(() => { jest.clearAllMocks(); diff --git a/tests/unit/userService.profile.test.js b/tests/unit/userService.profile.test.js index 6ba1185..6407cf7 100644 --- a/tests/unit/userService.profile.test.js +++ b/tests/unit/userService.profile.test.js @@ -1,12 +1,19 @@ /** * @fileoverview Unit Tests for User Service - Profile Operations * @module tests/unit/userService.profile.test + * + * Tests user profile service functions: get, update, delete operations. + * Validates data sanitization (password removal) and email uniqueness. */ import * as userService from '../../services/userService.js'; import db from '../../config/db.js'; import { ValidationError, NotFoundError, ConflictError } from '../../utils/errors.js'; +/** + * Test suite for user profile service operations. + * Covers getUserProfile, updateUserProfile, deleteUser, getAllUsers. + */ describe('User Service - Profile Operations', () => { let testUser; diff --git a/tests/unit/userService.settings.test.js b/tests/unit/userService.settings.test.js index e663722..1c159f7 100644 --- a/tests/unit/userService.settings.test.js +++ b/tests/unit/userService.settings.test.js @@ -1,15 +1,23 @@ /** * @fileoverview Unit Tests for User Service - Settings Operations * @module tests/unit/userService.settings.test + * + * Tests user settings management including language preferences, + * notifications, accessibility settings, and privacy options. */ import * as userService from '../../services/userService.js'; import db from '../../config/db.js'; import { ValidationError, NotFoundError } from '../../utils/errors.js'; +/** + * Test suite for user settings service functions. + * Covers getUserSettings and updateUserSettings operations. + */ describe('User Service - Settings Operations', () => { let testUser; + // Create fresh test user before each test beforeEach(async () => { // Create a test user in DB testUser = await db.createUser({ diff --git a/tests/unit/validation.behavior.test.js b/tests/unit/validation.behavior.test.js index 08c0236..71694a9 100644 --- a/tests/unit/validation.behavior.test.js +++ b/tests/unit/validation.behavior.test.js @@ -1,10 +1,19 @@ /** * @fileoverview Validation Middleware Tests - Function Behavior * @module tests/unit/validation.behavior.test + * + * Tests validation middleware behavior by simulating express-validator + * patterns. Verifies correct next() calls and error response formatting. */ +/** + * Test suite for validation middleware behavior patterns. + * Simulates express-validator error objects without actual middleware imports. + */ describe('Validation Middleware - Behavior', () => { + // Tests validate function's decision logic for pass/fail scenarios describe('validate function behavior', () => { + // Verifies next() is called when no validation errors exist it('should call next() when validation passes (no errors)', () => { const errors = { isEmpty: () => true, diff --git a/tests/unit/validation.formatting.test.js b/tests/unit/validation.formatting.test.js index 496b7b6..82c5050 100644 --- a/tests/unit/validation.formatting.test.js +++ b/tests/unit/validation.formatting.test.js @@ -1,11 +1,19 @@ /** * @fileoverview Validation Middleware Tests - Formatting * @module tests/unit/validation.formatting.test + * + * Tests validation error formatting and middleware export verification. + * Ensures errors are transformed into consistent API response format. */ import { validate } from '../../middleware/validation.js'; +/** + * Test suite for validation error formatting. + * Verifies error transformation from express-validator to API format. + */ describe('Validation Middleware - Formatting', () => { + // Tests for error message structure transformation describe('error formatting', () => { it('should format validation errors correctly', () => { const mockErrors = [ diff --git a/tests/unit/validators.additional.test.js b/tests/unit/validators.additional.test.js index ac444eb..51c75ce 100644 --- a/tests/unit/validators.additional.test.js +++ b/tests/unit/validators.additional.test.js @@ -1,6 +1,9 @@ /** * @fileoverview Validators Tests - Additional Validators * @module tests/unit/validators.additional.test + * + * Tests additional input validation functions: string sanitization, + * required field checking, and format validators for phone, URL, and date. */ import { @@ -12,8 +15,13 @@ import { isValidDate } from '../../utils/validators.js'; +/** + * Test suite for additional validation utility functions. + * Validates sanitization, field requirements, and format validations. + */ describe('Additional Validators - Unit Tests', () => { + // Tests string trimming and length limiting behavior describe('sanitizeString()', () => { it('should trim and limit string length', () => { diff --git a/tests/unit/validators.test.js b/tests/unit/validators.test.js index 3e3d191..186c32e 100644 --- a/tests/unit/validators.test.js +++ b/tests/unit/validators.test.js @@ -28,8 +28,10 @@ import { MIN_PASSWORD_LENGTH, MIN_RATING, MAX_RATING } from '../../config/consta describe('Validators - Core Functions', () => { + // Tests for email format validation using regex describe('isValidEmail()', () => { + // Valid email formats should return true describe('Happy Path - Valid Emails', () => { it('should return true for valid email', () => { expect(isValidEmail('test@example.com')).toBe(true); @@ -61,8 +63,10 @@ describe('Validators - Core Functions', () => { }); + // Tests for password strength validation describe('validatePassword()', () => { + // Valid passwords meeting minimum length should pass describe('Happy Path - Valid Passwords', () => { it('should return isValid: true for valid password', () => { const result = validatePassword('validPassword123'); @@ -93,8 +97,10 @@ describe('Validators - Core Functions', () => { }); + // Tests for rating value validation (1-5 integer range) describe('isValidRating()', () => { + // Ratings within bounds should be valid describe('Happy Path - Valid Ratings', () => { it('should return true for rating within limits', () => { expect(isValidRating(1)).toBe(true); @@ -126,8 +132,10 @@ describe('Validators - Core Functions', () => { }); + // Tests for geographic coordinate validation describe('isValidCoordinates()', () => { + // Lat/lng within bounds should be valid describe('Happy Path - Valid Coordinates', () => { it('should return true for valid coordinates', () => { expect(isValidCoordinates(37.9838, 23.7275)).toBe(true); diff --git a/utils/hateoas/userLinks.js b/utils/hateoas/userLinks.js index 7b80f84..d6a1f74 100644 --- a/utils/hateoas/userLinks.js +++ b/utils/hateoas/userLinks.js @@ -1,10 +1,18 @@ /** * @fileoverview HATEOAS User Links * @module utils/hateoas/userLinks + * + * Generates hypermedia links for user-related resources. + * Provides discoverability for REST API endpoints following HATEOAS principles. + * Each function returns an object with related links including HTTP methods. */ +/** + * HATEOAS link generators for user resources. + * Each method returns links with href and method for related actions. + */ const userLinks = { - // User Profile Links + // Generates links for user profile resource userProfile: (userId) => ({ self: { href: `/users/${userId}/profile`,