Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"cors": "^2.8.5",
"express": "^4.21.2",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1"
"swagger-ui-express": "^5.0.1",
"zod": "^4.4.3"
},
"devDependencies": {
"@types/express": "^5.0.0",
Expand Down
94 changes: 94 additions & 0 deletions api/src/routes/product.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { describe, it, expect, beforeEach } from 'vitest';
import request from 'supertest';
import express from 'express';
import productRouter, { resetProducts } from './product';
import { products as seedProducts } from '../seedData';

let app: express.Express;

describe('Product API', () => {
beforeEach(() => {
app = express();
app.use(express.json());
app.use('/products', productRouter);
resetProducts();
});

it('should create a new product with valid fields', async () => {
const newProduct = {
productId: 99,
supplierId: 1,
name: 'Test Product',
description: 'A test product',
price: 49.99,
sku: 'TEST-001',
unit: 'piece',
imgName: 'test.png',
};
const response = await request(app).post('/products').send(newProduct);
expect(response.status).toBe(201);
expect(response.body).toEqual(newProduct);
});

it('should return 400 when name is missing', async () => {
const invalidProduct = {
productId: 99,
supplierId: 1,
price: 49.99,
};
const response = await request(app).post('/products').send(invalidProduct);
expect(response.status).toBe(400);
expect(response.body).toHaveProperty('error', 'Validation failed');
});

it('should return 400 when price is missing', async () => {
const invalidProduct = {
productId: 99,
supplierId: 1,
name: 'Test Product',
};
const response = await request(app).post('/products').send(invalidProduct);
expect(response.status).toBe(400);
expect(response.body).toHaveProperty('error', 'Validation failed');
});

it('should return 400 when supplierId is missing', async () => {
const invalidProduct = {
productId: 99,
name: 'Test Product',
price: 49.99,
};
const response = await request(app).post('/products').send(invalidProduct);
expect(response.status).toBe(400);
expect(response.body).toHaveProperty('error', 'Validation failed');
});

it('should return 400 when price is not a positive number', async () => {
const invalidProduct = {
productId: 99,
supplierId: 1,
name: 'Test Product',
price: -10,
};
const response = await request(app).post('/products').send(invalidProduct);
expect(response.status).toBe(400);
expect(response.body).toHaveProperty('error', 'Validation failed');
});

it('should get all products', async () => {
const response = await request(app).get('/products');
expect(response.status).toBe(200);
expect(response.body.length).toBe(seedProducts.length);
});

it('should get a product by ID', async () => {
const response = await request(app).get('/products/1');
expect(response.status).toBe(200);
expect(response.body).toEqual(seedProducts[0]);
});

it('should return 404 for non-existing product', async () => {
const response = await request(app).get('/products/999');
expect(response.status).toBe(404);
});
});
23 changes: 20 additions & 3 deletions api/src/routes/product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,35 @@
*/

import express from 'express';
import { z } from 'zod';
import { Product } from '../models/product';
import { products as seedProducts } from '../seedData';

const router = express.Router();

let products: Product[] = [...seedProducts];

// Add reset function for testing
export const resetProducts = () => {
products = [...seedProducts];
};

const productSchema = z.object({
name: z.string().min(1),
price: z.number().positive(),
supplierId: z.number().int().positive(),
});

// Create a new product
router.post('/', (req, res) => {
const newProduct: Product = req.body;
products.push(newProduct);
res.status(201).json(newProduct);
const result = productSchema.safeParse(req.body);
if (!result.success) {
res.status(400).json({ error: 'Validation failed', details: result.error.issues });
} else {
const newProduct: Product = req.body;
products.push(newProduct);
res.status(201).json(newProduct);
}
});

// Get all products
Expand Down
12 changes: 11 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.