UNPKG

qmemory

Version:

A comprehensive production-ready Node.js utility library with MongoDB document operations, user ownership enforcement, Express.js HTTP utilities, environment-aware logging, and in-memory storage. Features 96%+ test coverage with comprehensive error handli

376 lines (291 loc) 15 kB
/** * Unit tests for MemStorage class * Tests all storage operations including CRUD operations, edge cases, * and internal state management. */ const { MemStorage, storage } = require('../../lib/storage'); // load class and singleton describe('MemStorage Class', () => { // tests behavior of the in-memory storage implementation let memStorage; beforeEach(() => { memStorage = new MemStorage(); // use default 10000 limit }); describe('constructor', () => { // ensure initialization logic sets up state correctly test('should initialize with empty users Map', () => { // constructor sets clean state expect(memStorage.users.size).toBe(0); }); test('should initialize currentId to 1', () => { // ID counter starts at 1 expect(memStorage.currentId).toBe(1); }); test('should create independent instances', () => { // instances have separate maps const storage1 = new MemStorage(); const storage2 = new MemStorage(); expect(storage1.users).not.toBe(storage2.users); expect(storage1.currentId).toBe(storage2.currentId); }); test('should set default maxUsers to 10000', () => { // default limit check expect(memStorage.maxUsers).toBe(10000); }); test('should accept custom maxUsers', () => { // custom limit constructor const custom = new MemStorage(5); expect(custom.maxUsers).toBe(5); }); test('should throw error for non-integer maxUsers', () => { // enforce integer check expect(() => new MemStorage(2.5)).toThrow('maxUsers must be a positive integer'); }); test('should throw error for non-positive maxUsers', () => { // enforce positive check expect(() => new MemStorage(0)).toThrow('maxUsers must be a positive integer'); }); test('should throw error for non-numeric maxUsers', () => { // enforce type check expect(() => new MemStorage('five')).toThrow('maxUsers must be a positive integer'); }); }); describe('createUser', () => { // validate user creation logic and field handling test('should create user with auto-generated ID', async () => { // creates minimal user const insertUser = { username: 'testuser', // Minimal required field displayName: 'Test User' // Optional field included for completeness }; const user = await memStorage.createUser(insertUser); expect(user).toMatchObject({ id: 1, username: 'testuser', displayName: 'Test User', githubId: null, avatar: null // Defaults should be null when not provided }); }); test('should increment ID for subsequent users', async () => { // verifies auto-increment const user1 = await memStorage.createUser({ username: 'user1' }); const user2 = await memStorage.createUser({ username: 'user2' }); expect(user1.id).toBe(1); expect(user2.id).toBe(2); }); test('should convert undefined fields to null', async () => { // normalizes undefined const insertUser = { username: 'testuser', displayName: undefined, githubId: undefined, avatar: undefined }; const user = await memStorage.createUser(insertUser); expect(user.displayName).toBeNull(); expect(user.githubId).toBeNull(); expect(user.avatar).toBeNull(); }); test('should preserve null values', async () => { // keeps explicit nulls const insertUser = { username: 'testuser', displayName: null, githubId: null, avatar: null }; const user = await memStorage.createUser(insertUser); expect(user.displayName).toBeNull(); expect(user.githubId).toBeNull(); expect(user.avatar).toBeNull(); }); test('should preserve falsy non-null values', async () => { // ensures values like 0 remain const insertUser = { username: 'testuser', displayName: '', githubId: '0', avatar: false }; const user = await memStorage.createUser(insertUser); expect(user.displayName).toBe(''); expect(user.githubId).toBe('0'); expect(user.avatar).toBe(false); }); test('should throw error for invalid username', async () => { // validates username input await expect(memStorage.createUser(null)).rejects.toThrow('Username is required and must be a non-empty string'); await expect(memStorage.createUser({})).rejects.toThrow('Username is required and must be a non-empty string'); await expect(memStorage.createUser({ username: '' })).rejects.toThrow('Username is required and must be a non-empty string'); await expect(memStorage.createUser({ username: ' ' })).rejects.toThrow('Username is required and must be a non-empty string'); await expect(memStorage.createUser({ username: 123 })).rejects.toThrow('Username is required and must be a non-empty string'); }); // Tests new input validation for production safety test('should throw error for duplicate username', async () => { // uniqueness enforced await memStorage.createUser({ username: 'testuser' }); await expect(memStorage.createUser({ username: 'testuser' })).rejects.toThrow("Username 'testuser' already exists"); }); // Tests new uniqueness validation for production safety test('should trim username and detect duplicates with spacing', async () => { // spaces should not avoid duplicate const user = await memStorage.createUser({ username: ' user ' }); expect(user.username).toBe('user'); await expect(memStorage.createUser({ username: 'user' })).rejects.toThrow("Username 'user' already exists"); }); test('should store user with all fields', async () => { // handles full payload const insertUser = { username: 'fulluser', displayName: 'Full User', githubId: 'github123', avatar: 'https://example.com/avatar.jpg' }; const user = await memStorage.createUser(insertUser); expect(user).toMatchObject({ id: 1, username: 'fulluser', displayName: 'Full User', githubId: 'github123', avatar: 'https://example.com/avatar.jpg' }); }); test('should allow creating users up to the limit', async () => { // verify maxUsers boundary const limited = new MemStorage(2); await limited.createUser({ username: 'a' }); await limited.createUser({ username: 'b' }); expect(limited.users.size).toBe(2); }); test('should throw error when exceeding maxUsers', async () => { // enforce limit reached const limited = new MemStorage(1); await limited.createUser({ username: 'first' }); await expect(limited.createUser({ username: 'second' })).rejects.toThrow('Maximum user limit reached'); }); test('should handle concurrent createUser calls hitting limit', async () => { // second call rejected once full const limited = new MemStorage(1); const firstPromise = limited.createUser({ username: 'concurrent1' }); // start first user create const secondPromise = limited.createUser({ username: 'concurrent2' }); // start second user create await expect(secondPromise).rejects.toThrow('Maximum user limit reached'); const firstUser = await firstPromise; expect(firstUser.username).toBe('concurrent1'); const allUsers = await limited.getAllUsers(); expect(allUsers).toHaveLength(1); }); }); describe('getUser', () => { // ensure retrieval by ID behaves as expected test('should return user by ID', async () => { // retrieves existing user const created = await memStorage.createUser({ username: 'testuser' }); const retrieved = await memStorage.getUser(1); expect(retrieved).toEqual(created); }); test('should return undefined for non-existent user', async () => { // handles missing id const user = await memStorage.getUser(999); expect(user).toBeUndefined(); }); test('should return undefined for invalid ID types', async () => { // validates id input expect(await memStorage.getUser(null)).toBeUndefined(); expect(await memStorage.getUser(undefined)).toBeUndefined(); expect(await memStorage.getUser('string')).toBeUndefined(); expect(await memStorage.getUser({})).toBeUndefined(); expect(await memStorage.getUser(0)).toBeUndefined(); // Zero not allowed expect(await memStorage.getUser(-1)).toBeUndefined(); // Negative not allowed }); // Tests new input validation for production safety }); describe('getUserByUsername', () => { // tests linear search by username test('should return user by username', async () => { // finds by unique key const created = await memStorage.createUser({ username: 'findme' }); const found = await memStorage.getUserByUsername('findme'); expect(found).toEqual(created); }); test('should return undefined for non-existent username', async () => { // not found case const user = await memStorage.getUserByUsername('nonexistent'); expect(user).toBeUndefined(); }); test('should handle case-sensitive username search', async () => { // usernames are case-sensitive await memStorage.createUser({ username: 'CaseTest' }); const exactMatch = await memStorage.getUserByUsername('CaseTest'); const lowerCase = await memStorage.getUserByUsername('casetest'); expect(exactMatch).toBeDefined(); expect(lowerCase).toBeUndefined(); }); test('should find correct user among multiple users', async () => { // ensures scanning works await memStorage.createUser({ username: 'user1' }); const target = await memStorage.createUser({ username: 'target' }); await memStorage.createUser({ username: 'user3' }); const found = await memStorage.getUserByUsername('target'); expect(found).toEqual(target); }); test('should return undefined for invalid username types', async () => { // validates argument types expect(await memStorage.getUserByUsername(null)).toBeUndefined(); expect(await memStorage.getUserByUsername(undefined)).toBeUndefined(); expect(await memStorage.getUserByUsername('')).toBeUndefined(); expect(await memStorage.getUserByUsername(' ')).toBeUndefined(); expect(await memStorage.getUserByUsername(123)).toBeUndefined(); }); // Tests new input validation for production safety test('should handle username trimming', async () => { // trimming before lookup await memStorage.createUser({ username: 'trimtest' }); const found = await memStorage.getUserByUsername(' trimtest '); expect(found).toBeDefined(); expect(found.username).toBe('trimtest'); }); // Tests username normalization }); describe('getAllUsers', () => { // verify retrieval of all stored records test('should return empty array when no users exist', async () => { // handles empty storage const users = await memStorage.getAllUsers(); expect(users).toEqual([]); }); test('should return all users', async () => { // returns list of users const user1 = await memStorage.createUser({ username: 'user1' }); const user2 = await memStorage.createUser({ username: 'user2' }); const allUsers = await memStorage.getAllUsers(); expect(allUsers).toHaveLength(2); expect(allUsers).toContain(user1); expect(allUsers).toContain(user2); }); test('should return new array (not reference to internal storage)', async () => { // ensures immutability await memStorage.createUser({ username: 'user1' }); const users1 = await memStorage.getAllUsers(); const users2 = await memStorage.getAllUsers(); expect(users1).not.toBe(users2); expect(users1).toEqual(users2); }); }); describe('deleteUser', () => { // validate removal and return values test('should delete existing user and return true', async () => { // removes user properly await memStorage.createUser({ username: 'deleteme' }); const result = await memStorage.deleteUser(1); expect(result).toBe(true); expect(await memStorage.getUser(1)).toBeUndefined(); }); test('should return false for non-existent user', async () => { // handle unknown id const result = await memStorage.deleteUser(999); expect(result).toBe(false); }); test('should handle multiple deletions', async () => { // repeated delete operations await memStorage.createUser({ username: 'user1' }); await memStorage.createUser({ username: 'user2' }); const result1 = await memStorage.deleteUser(1); const result2 = await memStorage.deleteUser(2); const result3 = await memStorage.deleteUser(1); // Already deleted expect(result1).toBe(true); expect(result2).toBe(true); expect(result3).toBe(false); }); }); describe('clear', () => { // ensure storage reset works correctly test('should remove all users', async () => { // clearing empties storage await memStorage.createUser({ username: 'user1' }); await memStorage.createUser({ username: 'user2' }); await memStorage.clear(); const allUsers = await memStorage.getAllUsers(); expect(allUsers).toHaveLength(0); }); test('should reset ID counter', async () => { // ID resets after clear await memStorage.createUser({ username: 'user1' }); await memStorage.createUser({ username: 'user2' }); await memStorage.clear(); const newUser = await memStorage.createUser({ username: 'fresh' }); expect(newUser.id).toBe(1); }); test('should handle clearing empty storage', async () => { // clearing when already empty await expect(memStorage.clear()).resolves.toBeUndefined(); const allUsers = await memStorage.getAllUsers(); expect(allUsers).toHaveLength(0); }); }); }); describe('Storage Singleton', () => { // confirm exported instance persistence beforeEach(async () => { await storage.clear(); }); test('should export singleton instance', () => { // exported object is instance expect(storage).toBeInstanceOf(MemStorage); }); test('should maintain state across module imports', async () => { // ensures singleton retains data // This test verifies that the singleton pattern works const user = await storage.createUser({ username: 'persistent' }); // Re-require the module to simulate different imports delete require.cache[require.resolve('../../lib/storage')]; const { storage: reimportedStorage } = require('../../lib/storage'); // import again to verify singleton const found = await reimportedStorage.getUser(user.id); expect(found).toEqual(user); }); });