Initial commit: Inventory Barcode System
This commit is contained in:
165
__tests__/InventoryModel.test.js
Normal file
165
__tests__/InventoryModel.test.js
Normal file
@ -0,0 +1,165 @@
|
||||
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');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user