const Inventory = require('../models/Inventory'); describe('Inventory Model - Basic Tests', () => { test('should create inventory instance', () => { const inventory = new Inventory({ product_id: 1, current_level: 50, minimum_level: 10, updated_by: 'testuser' }); expect(inventory.product_id).toBe(1); expect(inventory.current_level).toBe(50); expect(inventory.minimum_level).toBe(10); expect(inventory.updated_by).toBe('testuser'); }); test('should validate required product_id', () => { const inventory = new Inventory({ current_level: 50, minimum_level: 10 }); const validation = inventory.validate(); expect(validation.isValid).toBe(false); expect(validation.errors).toContain('Product ID is required and must be a number'); }); test('should validate current_level is non-negative', () => { const inventory = new Inventory({ product_id: 1, current_level: -5, minimum_level: 10 }); const validation = inventory.validate(); expect(validation.isValid).toBe(false); expect(validation.errors).toContain('Current level must be a non-negative number'); }); test('should pass validation with valid data', () => { const inventory = new Inventory({ product_id: 1, current_level: 50, minimum_level: 10, maximum_level: 100, updated_by: 'testuser' }); const validation = inventory.validate(); expect(validation.isValid).toBe(true); expect(validation.errors).toHaveLength(0); }); test('should convert to JSON', () => { const inventoryData = { id: 1, product_id: 1, current_level: 50, minimum_level: 10, maximum_level: 100, last_updated: '2023-01-01 00:00:00', updated_by: 'testuser', version: 1 }; const inventory = new Inventory(inventoryData); const json = inventory.toJSON(); expect(json).toEqual(inventoryData); }); }); describe('Inventory Model - Database Tests', () => { const database = require('../models/database'); let testProduct; beforeAll(async () => { // Initialize database for testing database.initialize(); }); afterAll(() => { // Close database connection database.close(); }); beforeEach(() => { // Clear tables before each test const db = database.getDatabase(); db.exec('DELETE FROM inventory_history'); db.exec('DELETE FROM inventory'); db.exec('DELETE FROM products'); // Create a test product const insertStmt = db.prepare(` INSERT INTO products (product_code, description, category, unit_of_measure) VALUES (?, ?, ?, ?) `); const result = insertStmt.run('TEST001', 'Test Product', 'Electronics', 'pieces'); testProduct = { id: result.lastInsertRowid, product_code: 'TEST001' }; }); test('should create inventory record for a product', async () => { const inventory = await Inventory.createForProduct( testProduct.id, 100, 10, 200, 'testuser' ); expect(inventory.product_id).toBe(testProduct.id); expect(inventory.current_level).toBe(100); expect(inventory.minimum_level).toBe(10); expect(inventory.maximum_level).toBe(200); expect(inventory.updated_by).toBe('testuser'); expect(inventory.id).toBeDefined(); }); test('should update inventory level and create audit record', async () => { // Create initial inventory await Inventory.createForProduct(testProduct.id, 100, 10, 200, 'system'); const updatedInventory = await Inventory.updateInventoryLevel( testProduct.id, 150, 'Restocking from supplier', 'testuser' ); expect(updatedInventory.product_id).toBe(testProduct.id); expect(updatedInventory.current_level).toBe(150); expect(updatedInventory.updated_by).toBe('testuser'); expect(updatedInventory.version).toBe(2); // Version should increment // Verify audit trail was created const history = await Inventory.getInventoryHistory(testProduct.id); expect(history).toHaveLength(2); // Initial creation + update expect(history[0].old_level).toBe(100); expect(history[0].new_level).toBe(150); expect(history[0].change_reason).toBe('Restocking from supplier'); expect(history[0].updated_by).toBe('testuser'); }); test('should handle concurrent updates with optimistic locking', async () => { // Create initial inventory await Inventory.createForProduct(testProduct.id, 100, 10, 200, 'system'); // Simulate concurrent access by getting the same record twice const inventory1 = await Inventory.getByProductId(testProduct.id); const inventory2 = await Inventory.getByProductId(testProduct.id); // First update should succeed inventory1.current_level = 120; inventory1.updated_by = 'user1'; await inventory1.save(); // Second update should fail due to version mismatch inventory2.current_level = 110; inventory2.updated_by = 'user2'; await expect(inventory2.save()).rejects.toThrow('Concurrent update detected'); }); });