717 lines
22 KiB
JavaScript
717 lines
22 KiB
JavaScript
const request = require('supertest');
|
|
const app = require('../server');
|
|
const Inventory = require('../models/Inventory');
|
|
const Product = require('../models/Product');
|
|
const database = require('../models/database');
|
|
|
|
// Mock the database and models
|
|
jest.mock('../models/database');
|
|
jest.mock('../models/Inventory');
|
|
jest.mock('../models/Product');
|
|
|
|
describe('Inventory API Endpoints', () => {
|
|
let mockDb;
|
|
|
|
beforeEach(() => {
|
|
// Reset all mocks
|
|
jest.clearAllMocks();
|
|
|
|
// Create mock database instance
|
|
mockDb = {
|
|
prepare: jest.fn(),
|
|
transaction: jest.fn()
|
|
};
|
|
|
|
database.getDatabase.mockReturnValue(mockDb);
|
|
database.getInstance = jest.fn().mockReturnValue(mockDb);
|
|
database.executeTransaction = jest.fn();
|
|
});
|
|
|
|
describe('GET /api/inventory', () => {
|
|
it('should return inventory summary for all products', async () => {
|
|
const mockInventorySummary = [
|
|
{
|
|
id: 1,
|
|
product_code: 'P001',
|
|
description: 'Product 1',
|
|
current_level: 10,
|
|
minimum_level: 5,
|
|
stock_status: 'normal'
|
|
},
|
|
{
|
|
id: 2,
|
|
product_code: 'P002',
|
|
description: 'Product 2',
|
|
current_level: 2,
|
|
minimum_level: 5,
|
|
stock_status: 'low'
|
|
}
|
|
];
|
|
|
|
Inventory.getInventorySummary.mockResolvedValue(mockInventorySummary);
|
|
|
|
const response = await request(app)
|
|
.get('/api/inventory')
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data).toHaveLength(2);
|
|
expect(response.body.count).toBe(2);
|
|
expect(Inventory.getInventorySummary).toHaveBeenCalledWith({});
|
|
});
|
|
|
|
it('should filter inventory by category', async () => {
|
|
const mockInventorySummary = [
|
|
{
|
|
id: 1,
|
|
product_code: 'P001',
|
|
description: 'Product 1',
|
|
category: 'Electronics',
|
|
current_level: 10
|
|
}
|
|
];
|
|
|
|
Inventory.getInventorySummary.mockResolvedValue(mockInventorySummary);
|
|
|
|
const response = await request(app)
|
|
.get('/api/inventory?category=Electronics')
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(Inventory.getInventorySummary).toHaveBeenCalledWith({ category: 'Electronics' });
|
|
});
|
|
|
|
it('should filter for low stock items', async () => {
|
|
const mockLowStockSummary = [
|
|
{
|
|
id: 2,
|
|
product_code: 'P002',
|
|
description: 'Product 2',
|
|
current_level: 2,
|
|
minimum_level: 5,
|
|
stock_status: 'low'
|
|
}
|
|
];
|
|
|
|
Inventory.getInventorySummary.mockResolvedValue(mockLowStockSummary);
|
|
|
|
const response = await request(app)
|
|
.get('/api/inventory?lowStock=true')
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(Inventory.getInventorySummary).toHaveBeenCalledWith({ lowStock: true });
|
|
});
|
|
|
|
it('should handle database errors gracefully', async () => {
|
|
Inventory.getInventorySummary.mockRejectedValue(new Error('Database connection failed'));
|
|
|
|
const response = await request(app)
|
|
.get('/api/inventory')
|
|
.expect(500);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Failed to retrieve inventory summary');
|
|
});
|
|
});
|
|
|
|
describe('GET /api/inventory/low-stock', () => {
|
|
it('should return low stock items', async () => {
|
|
const mockLowStockItems = [
|
|
{
|
|
id: 1,
|
|
product_code: 'P001',
|
|
description: 'Low Stock Product',
|
|
current_level: 2,
|
|
minimum_level: 10
|
|
}
|
|
];
|
|
|
|
Inventory.getLowStockItems.mockResolvedValue(mockLowStockItems);
|
|
|
|
const response = await request(app)
|
|
.get('/api/inventory/low-stock')
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data).toHaveLength(1);
|
|
expect(response.body.count).toBe(1);
|
|
});
|
|
|
|
it('should handle errors when retrieving low stock items', async () => {
|
|
Inventory.getLowStockItems.mockRejectedValue(new Error('Database error'));
|
|
|
|
const response = await request(app)
|
|
.get('/api/inventory/low-stock')
|
|
.expect(500);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Failed to retrieve low stock items');
|
|
});
|
|
});
|
|
|
|
describe('GET /api/inventory/product/:productId', () => {
|
|
it('should return inventory details for a specific product', async () => {
|
|
const mockInventory = {
|
|
id: 1,
|
|
product_id: 1,
|
|
current_level: 15,
|
|
minimum_level: 5,
|
|
maximum_level: 50,
|
|
toJSON: jest.fn().mockReturnValue({
|
|
id: 1,
|
|
product_id: 1,
|
|
current_level: 15,
|
|
minimum_level: 5,
|
|
maximum_level: 50
|
|
})
|
|
};
|
|
|
|
Inventory.getByProductId.mockResolvedValue(mockInventory);
|
|
|
|
const response = await request(app)
|
|
.get('/api/inventory/product/1')
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data.product_id).toBe(1);
|
|
expect(response.body.data.current_level).toBe(15);
|
|
});
|
|
|
|
it('should return 404 for non-existent inventory', async () => {
|
|
Inventory.getByProductId.mockResolvedValue(null);
|
|
|
|
const response = await request(app)
|
|
.get('/api/inventory/product/999')
|
|
.expect(404);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Inventory not found');
|
|
});
|
|
|
|
it('should return 400 for invalid product ID', async () => {
|
|
const response = await request(app)
|
|
.get('/api/inventory/product/invalid')
|
|
.expect(400);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Invalid product ID');
|
|
});
|
|
});
|
|
|
|
describe('GET /api/inventory/product/:productId/level', () => {
|
|
it('should return current inventory level', async () => {
|
|
Inventory.getCurrentLevel.mockResolvedValue(25);
|
|
|
|
const response = await request(app)
|
|
.get('/api/inventory/product/1/level')
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data.product_id).toBe(1);
|
|
expect(response.body.data.current_level).toBe(25);
|
|
});
|
|
|
|
it('should return 400 for invalid product ID', async () => {
|
|
const response = await request(app)
|
|
.get('/api/inventory/product/invalid/level')
|
|
.expect(400);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Invalid product ID');
|
|
});
|
|
});
|
|
|
|
describe('GET /api/inventory/product/:productId/history', () => {
|
|
it('should return inventory history with default pagination', async () => {
|
|
const mockHistory = [
|
|
{
|
|
id: 1,
|
|
product_id: 1,
|
|
old_level: 10,
|
|
new_level: 15,
|
|
change_reason: 'Stock received',
|
|
updated_at: '2023-01-01T10:00:00Z'
|
|
}
|
|
];
|
|
|
|
Inventory.getInventoryHistory.mockResolvedValue(mockHistory);
|
|
|
|
const response = await request(app)
|
|
.get('/api/inventory/product/1/history')
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data).toHaveLength(1);
|
|
expect(response.body.pagination.limit).toBe(50);
|
|
expect(response.body.pagination.offset).toBe(0);
|
|
expect(Inventory.getInventoryHistory).toHaveBeenCalledWith(1, {
|
|
limit: 50,
|
|
offset: 0,
|
|
startDate: undefined,
|
|
endDate: undefined
|
|
});
|
|
});
|
|
|
|
it('should return inventory history with custom pagination', async () => {
|
|
const mockHistory = [];
|
|
Inventory.getInventoryHistory.mockResolvedValue(mockHistory);
|
|
|
|
const response = await request(app)
|
|
.get('/api/inventory/product/1/history?limit=10&offset=20')
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.pagination.limit).toBe(10);
|
|
expect(response.body.pagination.offset).toBe(20);
|
|
expect(Inventory.getInventoryHistory).toHaveBeenCalledWith(1, {
|
|
limit: 10,
|
|
offset: 20,
|
|
startDate: undefined,
|
|
endDate: undefined
|
|
});
|
|
});
|
|
|
|
it('should return 400 for invalid limit', async () => {
|
|
const response = await request(app)
|
|
.get('/api/inventory/product/1/history?limit=2000')
|
|
.expect(400);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Invalid limit');
|
|
});
|
|
|
|
it('should return 400 for negative offset', async () => {
|
|
const response = await request(app)
|
|
.get('/api/inventory/product/1/history?offset=-1')
|
|
.expect(400);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Invalid offset');
|
|
});
|
|
});
|
|
|
|
describe('PUT /api/inventory/product/:productId/level', () => {
|
|
it('should update inventory level successfully', async () => {
|
|
const mockProduct = { id: 1, name: 'Test Product' };
|
|
const mockUpdatedInventory = {
|
|
id: 1,
|
|
product_id: 1,
|
|
current_level: 20,
|
|
toJSON: jest.fn().mockReturnValue({
|
|
id: 1,
|
|
product_id: 1,
|
|
current_level: 20
|
|
})
|
|
};
|
|
|
|
Product.findById.mockResolvedValue(mockProduct);
|
|
Inventory.updateInventoryLevel.mockResolvedValue(mockUpdatedInventory);
|
|
|
|
const response = await request(app)
|
|
.put('/api/inventory/product/1/level')
|
|
.send({
|
|
newLevel: 20,
|
|
changeReason: 'Stock adjustment',
|
|
updatedBy: 'test-user'
|
|
})
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data.current_level).toBe(20);
|
|
expect(response.body.message).toBe('Inventory level updated successfully');
|
|
expect(Inventory.updateInventoryLevel).toHaveBeenCalledWith(
|
|
1,
|
|
20,
|
|
'Stock adjustment',
|
|
'test-user'
|
|
);
|
|
});
|
|
|
|
it('should return 400 for invalid new level', async () => {
|
|
const response = await request(app)
|
|
.put('/api/inventory/product/1/level')
|
|
.send({ newLevel: 'invalid' })
|
|
.expect(400);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Invalid new level');
|
|
});
|
|
|
|
it('should return 400 for negative new level', async () => {
|
|
const response = await request(app)
|
|
.put('/api/inventory/product/1/level')
|
|
.send({ newLevel: -5 })
|
|
.expect(400);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Invalid new level');
|
|
});
|
|
|
|
it('should return 404 for non-existent product', async () => {
|
|
Product.findById.mockResolvedValue(null);
|
|
|
|
const response = await request(app)
|
|
.put('/api/inventory/product/999/level')
|
|
.send({ newLevel: 10 })
|
|
.expect(404);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Product not found');
|
|
});
|
|
|
|
it('should return 409 for concurrent update conflict', async () => {
|
|
const mockProduct = { id: 1, name: 'Test Product' };
|
|
Product.findById.mockResolvedValue(mockProduct);
|
|
Inventory.updateInventoryLevel.mockRejectedValue(
|
|
new Error('Concurrent update detected. Please refresh and try again.')
|
|
);
|
|
|
|
const response = await request(app)
|
|
.put('/api/inventory/product/1/level')
|
|
.send({ newLevel: 10 })
|
|
.expect(409);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Concurrent update conflict');
|
|
});
|
|
});
|
|
|
|
describe('PUT /api/inventory/product/:productId', () => {
|
|
it('should update inventory settings successfully', async () => {
|
|
const mockProduct = { id: 1, name: 'Test Product' };
|
|
const mockInventory = {
|
|
id: 1,
|
|
product_id: 1,
|
|
current_level: 15,
|
|
minimum_level: 5,
|
|
maximum_level: 50,
|
|
version: 1,
|
|
validate: jest.fn().mockReturnValue({ isValid: true, errors: [] }),
|
|
save: jest.fn().mockResolvedValue(true),
|
|
toJSON: jest.fn().mockReturnValue({
|
|
id: 1,
|
|
product_id: 1,
|
|
current_level: 15,
|
|
minimum_level: 10,
|
|
maximum_level: 100
|
|
})
|
|
};
|
|
|
|
Product.findById.mockResolvedValue(mockProduct);
|
|
Inventory.getByProductId.mockResolvedValue(mockInventory);
|
|
|
|
const response = await request(app)
|
|
.put('/api/inventory/product/1')
|
|
.send({
|
|
minimum_level: 10,
|
|
maximum_level: 100,
|
|
updatedBy: 'test-user'
|
|
})
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.message).toBe('Inventory settings updated successfully');
|
|
expect(mockInventory.minimum_level).toBe(10);
|
|
expect(mockInventory.maximum_level).toBe(100);
|
|
expect(mockInventory.save).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should return 404 for non-existent inventory', async () => {
|
|
const mockProduct = { id: 1, name: 'Test Product' };
|
|
Product.findById.mockResolvedValue(mockProduct);
|
|
Inventory.getByProductId.mockResolvedValue(null);
|
|
|
|
const response = await request(app)
|
|
.put('/api/inventory/product/1')
|
|
.send({ minimum_level: 10 })
|
|
.expect(404);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Inventory not found');
|
|
});
|
|
|
|
it('should return 400 for invalid minimum level', async () => {
|
|
const mockProduct = { id: 1, name: 'Test Product' };
|
|
const mockInventory = { id: 1, product_id: 1 };
|
|
|
|
Product.findById.mockResolvedValue(mockProduct);
|
|
Inventory.getByProductId.mockResolvedValue(mockInventory);
|
|
|
|
const response = await request(app)
|
|
.put('/api/inventory/product/1')
|
|
.send({ minimum_level: -5 })
|
|
.expect(400);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Invalid minimum level');
|
|
});
|
|
});
|
|
|
|
describe('POST /api/inventory/product/:productId', () => {
|
|
it('should create inventory record successfully', async () => {
|
|
const mockProduct = { id: 1, name: 'Test Product' };
|
|
const mockInventory = {
|
|
id: 1,
|
|
product_id: 1,
|
|
current_level: 10,
|
|
toJSON: jest.fn().mockReturnValue({
|
|
id: 1,
|
|
product_id: 1,
|
|
current_level: 10
|
|
})
|
|
};
|
|
|
|
Product.findById.mockResolvedValue(mockProduct);
|
|
Inventory.getByProductId.mockResolvedValue(null); // No existing inventory
|
|
Inventory.createForProduct.mockResolvedValue(mockInventory);
|
|
|
|
const response = await request(app)
|
|
.post('/api/inventory/product/1')
|
|
.send({
|
|
initialLevel: 10,
|
|
minimumLevel: 5,
|
|
maximumLevel: 50,
|
|
updatedBy: 'test-user'
|
|
})
|
|
.expect(201);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.message).toBe('Inventory record created successfully');
|
|
expect(Inventory.createForProduct).toHaveBeenCalledWith(1, 10, 5, 50, 'test-user');
|
|
});
|
|
|
|
it('should return 409 if inventory already exists', async () => {
|
|
const mockProduct = { id: 1, name: 'Test Product' };
|
|
const mockExistingInventory = { id: 1, product_id: 1 };
|
|
|
|
Product.findById.mockResolvedValue(mockProduct);
|
|
Inventory.getByProductId.mockResolvedValue(mockExistingInventory);
|
|
|
|
const response = await request(app)
|
|
.post('/api/inventory/product/1')
|
|
.send({ initialLevel: 10 })
|
|
.expect(409);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Inventory already exists');
|
|
});
|
|
|
|
it('should return 400 for invalid initial level', async () => {
|
|
const mockProduct = { id: 1, name: 'Test Product' };
|
|
Product.findById.mockResolvedValue(mockProduct);
|
|
Inventory.getByProductId.mockResolvedValue(null);
|
|
|
|
const response = await request(app)
|
|
.post('/api/inventory/product/1')
|
|
.send({ initialLevel: -5 })
|
|
.expect(400);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Invalid initial level');
|
|
});
|
|
});
|
|
|
|
describe('POST /api/inventory/bulk-update', () => {
|
|
it('should bulk update inventory levels successfully', async () => {
|
|
const updates = [
|
|
{ productId: 1, newLevel: 20, changeReason: 'Restock', updatedBy: 'user1' },
|
|
{ productId: 2, newLevel: 15, changeReason: 'Adjustment', updatedBy: 'user1' }
|
|
];
|
|
|
|
const mockUpdatedInventories = [
|
|
{
|
|
id: 1,
|
|
product_id: 1,
|
|
current_level: 20,
|
|
toJSON: jest.fn().mockReturnValue({ id: 1, product_id: 1, current_level: 20 })
|
|
},
|
|
{
|
|
id: 2,
|
|
product_id: 2,
|
|
current_level: 15,
|
|
toJSON: jest.fn().mockReturnValue({ id: 2, product_id: 2, current_level: 15 })
|
|
}
|
|
];
|
|
|
|
Inventory.bulkUpdateInventory.mockResolvedValue(mockUpdatedInventories);
|
|
|
|
const response = await request(app)
|
|
.post('/api/inventory/bulk-update')
|
|
.send({ updates })
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.count).toBe(2);
|
|
expect(response.body.message).toBe('Successfully updated 2 inventory records');
|
|
expect(Inventory.bulkUpdateInventory).toHaveBeenCalledWith(updates);
|
|
});
|
|
|
|
it('should return 400 for empty updates array', async () => {
|
|
const response = await request(app)
|
|
.post('/api/inventory/bulk-update')
|
|
.send({ updates: [] })
|
|
.expect(400);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Invalid input');
|
|
});
|
|
|
|
it('should return 400 for invalid update data', async () => {
|
|
const updates = [
|
|
{ productId: 'invalid', newLevel: 20 }
|
|
];
|
|
|
|
const response = await request(app)
|
|
.post('/api/inventory/bulk-update')
|
|
.send({ updates })
|
|
.expect(400);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Invalid update data');
|
|
});
|
|
|
|
it('should return 409 for concurrent update conflict', async () => {
|
|
const updates = [{ productId: 1, newLevel: 20 }];
|
|
Inventory.bulkUpdateInventory.mockRejectedValue(
|
|
new Error('Concurrent update detected for product 1. Please refresh and try again.')
|
|
);
|
|
|
|
const response = await request(app)
|
|
.post('/api/inventory/bulk-update')
|
|
.send({ updates })
|
|
.expect(409);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Concurrent update conflict');
|
|
});
|
|
});
|
|
|
|
describe('POST /api/inventory/adjust/:productId', () => {
|
|
it('should adjust inventory level positively', async () => {
|
|
const mockProduct = { id: 1, name: 'Test Product' };
|
|
const mockUpdatedInventory = {
|
|
id: 1,
|
|
product_id: 1,
|
|
current_level: 25,
|
|
toJSON: jest.fn().mockReturnValue({
|
|
id: 1,
|
|
product_id: 1,
|
|
current_level: 25
|
|
})
|
|
};
|
|
|
|
Product.findById.mockResolvedValue(mockProduct);
|
|
Inventory.getCurrentLevel.mockResolvedValue(20);
|
|
Inventory.updateInventoryLevel.mockResolvedValue(mockUpdatedInventory);
|
|
|
|
const response = await request(app)
|
|
.post('/api/inventory/adjust/1')
|
|
.send({
|
|
adjustment: 5,
|
|
changeReason: 'Stock received',
|
|
updatedBy: 'test-user'
|
|
})
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data.current_level).toBe(25);
|
|
expect(response.body.data.adjustment).toBe(5);
|
|
expect(response.body.data.previous_level).toBe(20);
|
|
expect(Inventory.updateInventoryLevel).toHaveBeenCalledWith(
|
|
1,
|
|
25,
|
|
'Stock received',
|
|
'test-user'
|
|
);
|
|
});
|
|
|
|
it('should adjust inventory level negatively', async () => {
|
|
const mockProduct = { id: 1, name: 'Test Product' };
|
|
const mockUpdatedInventory = {
|
|
id: 1,
|
|
product_id: 1,
|
|
current_level: 15,
|
|
toJSON: jest.fn().mockReturnValue({
|
|
id: 1,
|
|
product_id: 1,
|
|
current_level: 15
|
|
})
|
|
};
|
|
|
|
Product.findById.mockResolvedValue(mockProduct);
|
|
Inventory.getCurrentLevel.mockResolvedValue(20);
|
|
Inventory.updateInventoryLevel.mockResolvedValue(mockUpdatedInventory);
|
|
|
|
const response = await request(app)
|
|
.post('/api/inventory/adjust/1')
|
|
.send({ adjustment: -5 })
|
|
.expect(200);
|
|
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data.current_level).toBe(15);
|
|
expect(response.body.data.adjustment).toBe(-5);
|
|
expect(Inventory.updateInventoryLevel).toHaveBeenCalledWith(
|
|
1,
|
|
15,
|
|
'Inventory adjustment: -5',
|
|
'api-user'
|
|
);
|
|
});
|
|
|
|
it('should return 400 for adjustment that would cause negative inventory', async () => {
|
|
const mockProduct = { id: 1, name: 'Test Product' };
|
|
Product.findById.mockResolvedValue(mockProduct);
|
|
Inventory.getCurrentLevel.mockResolvedValue(5);
|
|
|
|
const response = await request(app)
|
|
.post('/api/inventory/adjust/1')
|
|
.send({ adjustment: -10 })
|
|
.expect(400);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Invalid adjustment');
|
|
expect(response.body.message).toContain('would result in negative inventory');
|
|
});
|
|
|
|
it('should return 400 for invalid adjustment type', async () => {
|
|
const response = await request(app)
|
|
.post('/api/inventory/adjust/1')
|
|
.send({ adjustment: 'invalid' })
|
|
.expect(400);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Invalid adjustment');
|
|
});
|
|
});
|
|
|
|
describe('Error Handling', () => {
|
|
it('should handle database connection errors', async () => {
|
|
Inventory.getInventorySummary.mockRejectedValue(new Error('Database connection failed'));
|
|
|
|
const response = await request(app)
|
|
.get('/api/inventory')
|
|
.expect(500);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Failed to retrieve inventory summary');
|
|
});
|
|
|
|
it('should handle inventory not found errors', async () => {
|
|
Inventory.updateInventoryLevel.mockRejectedValue(
|
|
new Error('Inventory record for product ID 999 not found')
|
|
);
|
|
|
|
const mockProduct = { id: 999, name: 'Test Product' };
|
|
Product.findById.mockResolvedValue(mockProduct);
|
|
|
|
const response = await request(app)
|
|
.put('/api/inventory/product/999/level')
|
|
.send({ newLevel: 10 })
|
|
.expect(404);
|
|
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toBe('Inventory not found');
|
|
});
|
|
});
|
|
}); |