165 lines
5.5 KiB
JavaScript
165 lines
5.5 KiB
JavaScript
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');
|
|
});
|
|
}); |