Files
inventory-barcode-system/__tests__/Product.test.js

237 lines
7.4 KiB
JavaScript

const Product = require('../models/Product');
const database = require('../models/database');
describe('Product Model', () => {
beforeAll(async () => {
// Initialize database for testing
database.initialize();
});
afterAll(() => {
// Close database connection
database.close();
});
beforeEach(() => {
// Clear items table before each test
const db = database.getDatabase();
db.exec('DELETE FROM items');
});
describe('Validation', () => {
test('should validate required fields', () => {
const product = new Product();
const validation = product.validate();
expect(validation.isValid).toBe(false);
expect(validation.errors).toContain('Product name is required');
});
test('should validate product name length', () => {
const product = new Product({ name: 'a'.repeat(256) });
const validation = product.validate();
expect(validation.isValid).toBe(false);
expect(validation.errors).toContain('Product name must be less than 255 characters');
});
test('should validate quantity is non-negative number', () => {
const product = new Product({ name: 'Test Product', quantity: -1 });
const validation = product.validate();
expect(validation.isValid).toBe(false);
expect(validation.errors).toContain('Quantity must be a non-negative number');
});
test('should validate min_stock_level is non-negative number', () => {
const product = new Product({ name: 'Test Product', min_stock_level: -1 });
const validation = product.validate();
expect(validation.isValid).toBe(false);
expect(validation.errors).toContain('Minimum stock level must be a non-negative number');
});
test('should validate category length', () => {
const product = new Product({
name: 'Test Product',
category: 'a'.repeat(101)
});
const validation = product.validate();
expect(validation.isValid).toBe(false);
expect(validation.errors).toContain('Category must be less than 100 characters');
});
test('should validate unit length', () => {
const product = new Product({
name: 'Test Product',
unit: 'a'.repeat(21)
});
const validation = product.validate();
expect(validation.isValid).toBe(false);
expect(validation.errors).toContain('Unit must be less than 20 characters');
});
test('should pass validation with valid data', () => {
const product = new Product({
name: 'Test Product',
description: 'A test product',
category: 'Electronics',
quantity: 10,
unit: 'pieces',
barcode: '123456789',
location: 'A1-B2',
min_stock_level: 5
});
const validation = product.validate();
expect(validation.isValid).toBe(true);
expect(validation.errors).toHaveLength(0);
});
});
describe('Database Operations', () => {
test('should save new product to database', async () => {
const productData = {
name: 'Test Product',
description: 'A test product',
category: 'Electronics',
quantity: 10,
unit: 'pieces',
barcode: '123456789',
location: 'A1-B2',
min_stock_level: 5
};
const product = new Product(productData);
await product.save();
expect(product.id).toBeDefined();
expect(product.id).toBeGreaterThan(0);
});
test('should update existing product', async () => {
// First create a product
const product = new Product({
name: 'Test Product',
quantity: 10
});
await product.save();
// Update the product
product.name = 'Updated Product';
product.quantity = 20;
await product.save();
// Verify the update
const updatedProduct = await Product.findById(product.id);
expect(updatedProduct.name).toBe('Updated Product');
expect(updatedProduct.quantity).toBe(20);
});
test('should find product by ID', async () => {
const product = new Product({
name: 'Test Product',
barcode: '123456789'
});
await product.save();
const foundProduct = await Product.findById(product.id);
expect(foundProduct).toBeDefined();
expect(foundProduct.name).toBe('Test Product');
expect(foundProduct.barcode).toBe('123456789');
});
test('should find product by barcode', async () => {
const product = new Product({
name: 'Test Product',
barcode: '123456789'
});
await product.save();
const foundProduct = await Product.findByBarcode('123456789');
expect(foundProduct).toBeDefined();
expect(foundProduct.name).toBe('Test Product');
});
test('should return null when product not found', async () => {
const foundProduct = await Product.findById(999);
expect(foundProduct).toBeNull();
});
test('should find all products', async () => {
// Create multiple products
const product1 = new Product({ name: 'Product 1', category: 'Electronics' });
const product2 = new Product({ name: 'Product 2', category: 'Books' });
await product1.save();
await product2.save();
const allProducts = await Product.findAll();
expect(allProducts).toHaveLength(2);
});
test('should filter products by category', async () => {
const product1 = new Product({ name: 'Product 1', category: 'Electronics' });
const product2 = new Product({ name: 'Product 2', category: 'Books' });
await product1.save();
await product2.save();
const electronicsProducts = await Product.findAll({ category: 'Electronics' });
expect(electronicsProducts).toHaveLength(1);
expect(electronicsProducts[0].name).toBe('Product 1');
});
test('should delete product by ID', async () => {
const product = new Product({ name: 'Test Product' });
await product.save();
const deleted = await Product.deleteById(product.id);
expect(deleted).toBe(true);
const foundProduct = await Product.findById(product.id);
expect(foundProduct).toBeNull();
});
test('should handle unique barcode constraint', async () => {
const product1 = new Product({ name: 'Product 1', barcode: '123456789' });
await product1.save();
const product2 = new Product({ name: 'Product 2', barcode: '123456789' });
await expect(product2.save()).rejects.toThrow('A product with this barcode already exists');
});
test('should throw validation error when saving invalid product', async () => {
const product = new Product({ quantity: -1 }); // Invalid: no name and negative quantity
await expect(product.save()).rejects.toThrow('Validation failed');
});
});
describe('JSON Serialization', () => {
test('should convert product to JSON', () => {
const productData = {
id: 1,
name: 'Test Product',
description: 'A test product',
category: 'Electronics',
quantity: 10,
unit: 'pieces',
barcode: '123456789',
qr_code: 'QR123',
location: 'A1-B2',
min_stock_level: 5,
created_at: '2023-01-01 00:00:00',
updated_at: '2023-01-01 00:00:00'
};
const product = new Product(productData);
const json = product.toJSON();
expect(json).toEqual(productData);
});
});
});