All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 18m34s
175 lines
6.5 KiB
TypeScript
175 lines
6.5 KiB
TypeScript
// src/tests/integration/category.routes.test.ts
|
|
import { describe, it, expect, beforeAll } from 'vitest';
|
|
import supertest from 'supertest';
|
|
|
|
/**
|
|
* @vitest-environment node
|
|
*/
|
|
|
|
describe('Category API Routes (Integration)', () => {
|
|
let request: ReturnType<typeof supertest>;
|
|
|
|
beforeAll(async () => {
|
|
const app = (await import('../../../server')).default;
|
|
request = supertest(app);
|
|
});
|
|
|
|
describe('GET /api/categories', () => {
|
|
it('should return list of all categories', async () => {
|
|
const response = await request.get('/api/categories');
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body.success).toBe(true);
|
|
expect(Array.isArray(response.body.data)).toBe(true);
|
|
expect(response.body.data.length).toBeGreaterThan(0);
|
|
|
|
// Verify category structure
|
|
const firstCategory = response.body.data[0];
|
|
expect(firstCategory).toHaveProperty('category_id');
|
|
expect(firstCategory).toHaveProperty('name');
|
|
expect(firstCategory).toHaveProperty('created_at');
|
|
expect(firstCategory).toHaveProperty('updated_at');
|
|
expect(typeof firstCategory.category_id).toBe('number');
|
|
expect(typeof firstCategory.name).toBe('string');
|
|
});
|
|
|
|
it('should return categories in alphabetical order', async () => {
|
|
const response = await request.get('/api/categories');
|
|
const categories = response.body.data;
|
|
|
|
// Verify alphabetical ordering
|
|
for (let i = 1; i < categories.length; i++) {
|
|
const prevName = categories[i - 1].name.toLowerCase();
|
|
const currName = categories[i].name.toLowerCase();
|
|
expect(currName >= prevName).toBe(true);
|
|
}
|
|
});
|
|
|
|
it('should include expected categories', async () => {
|
|
const response = await request.get('/api/categories');
|
|
const categories = response.body.data;
|
|
const categoryNames = categories.map((c: { name: string }) => c.name);
|
|
|
|
// Verify some expected categories exist
|
|
expect(categoryNames).toContain('Dairy & Eggs');
|
|
expect(categoryNames).toContain('Fruits & Vegetables');
|
|
expect(categoryNames).toContain('Meat & Seafood');
|
|
expect(categoryNames).toContain('Bakery & Bread');
|
|
});
|
|
});
|
|
|
|
describe('GET /api/categories/:id', () => {
|
|
it('should return specific category by valid ID', async () => {
|
|
// First get all categories to find a valid ID
|
|
const listResponse = await request.get('/api/categories');
|
|
const firstCategory = listResponse.body.data[0];
|
|
|
|
const response = await request.get(`/api/categories/${firstCategory.category_id}`);
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data.category_id).toBe(firstCategory.category_id);
|
|
expect(response.body.data.name).toBe(firstCategory.name);
|
|
});
|
|
|
|
it('should return 404 for non-existent category ID', async () => {
|
|
const response = await request.get('/api/categories/999999');
|
|
|
|
expect(response.status).toBe(404);
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toContain('not found');
|
|
});
|
|
|
|
it('should return 400 for invalid category ID (not a number)', async () => {
|
|
const response = await request.get('/api/categories/invalid');
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toContain('Invalid category ID');
|
|
});
|
|
|
|
it('should return 400 for negative category ID', async () => {
|
|
const response = await request.get('/api/categories/-1');
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toContain('Invalid category ID');
|
|
});
|
|
|
|
it('should return 400 for zero category ID', async () => {
|
|
const response = await request.get('/api/categories/0');
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toContain('Invalid category ID');
|
|
});
|
|
});
|
|
|
|
describe('GET /api/categories/lookup', () => {
|
|
it('should find category by exact name', async () => {
|
|
const response = await request.get('/api/categories/lookup?name=Dairy%20%26%20Eggs');
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data.name).toBe('Dairy & Eggs');
|
|
expect(response.body.data.category_id).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('should find category by case-insensitive name', async () => {
|
|
const response = await request.get('/api/categories/lookup?name=dairy%20%26%20eggs');
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data.name).toBe('Dairy & Eggs');
|
|
});
|
|
|
|
it('should find category with mixed case', async () => {
|
|
const response = await request.get('/api/categories/lookup?name=DaIrY%20%26%20eGgS');
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data.name).toBe('Dairy & Eggs');
|
|
});
|
|
|
|
it('should return 404 for non-existent category name', async () => {
|
|
const response = await request.get('/api/categories/lookup?name=NonExistentCategory');
|
|
|
|
expect(response.status).toBe(404);
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toContain('not found');
|
|
});
|
|
|
|
it('should return 400 if name parameter is missing', async () => {
|
|
const response = await request.get('/api/categories/lookup');
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toContain('required');
|
|
});
|
|
|
|
it('should return 400 for empty name parameter', async () => {
|
|
const response = await request.get('/api/categories/lookup?name=');
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toContain('required');
|
|
});
|
|
|
|
it('should return 400 for whitespace-only name parameter', async () => {
|
|
const response = await request.get('/api/categories/lookup?name= ');
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(response.body.success).toBe(false);
|
|
expect(response.body.error).toContain('required');
|
|
});
|
|
|
|
it('should handle URL-encoded category names', async () => {
|
|
const response = await request.get('/api/categories/lookup?name=Dairy%20%26%20Eggs');
|
|
|
|
expect(response.status).toBe(200);
|
|
expect(response.body.success).toBe(true);
|
|
expect(response.body.data.name).toBe('Dairy & Eggs');
|
|
});
|
|
});
|
|
});
|