Files
flyer-crawler.projectium.com/src/tests/integration/category.routes.test.ts
Torben Sorensen 5879328b67
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 18m34s
fixing categories 3rd normal form
2026-01-19 19:13:30 -08:00

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');
});
});
});