import { Filament } from '../src/types/filament'; import { Pool } from 'pg'; describe('Data Structure Consistency Tests', () => { const connectionString = "postgresql://filamenteka_admin:onrBjiAjHKQXBAJSVWU2t2kQ7HDil9re@filamenteka.ci7fsdlbzmag.eu-central-1.rds.amazonaws.com:5432/filamenteka"; // Admin panel expected structure (source of truth) const ADMIN_STRUCTURE = { fields: [ 'id', 'tip', 'finish', 'boja', 'boja_hex', // Now using snake_case consistently 'refill', 'spulna', // Frontend still uses spulna 'kolicina', 'cena', 'created_at', 'updated_at' ], requiredFields: ['tip', 'finish', 'boja'], excludedFields: ['brand'], // Should NOT exist fieldTypes: { tip: 'string', finish: 'string', boja: 'string', boja_hex: 'string', refill: 'number', spulna: 'number', kolicina: 'number', cena: 'string' } }; // Database expected structure const DB_STRUCTURE = { columns: [ 'id', 'tip', 'finish', 'boja', 'boja_hex', // Database uses snake_case 'refill', 'spulna', 'kolicina', 'cena', 'created_at', 'updated_at' ], excludedColumns: ['brand'], columnTypes: { id: 'uuid', tip: 'character varying', finish: 'character varying', boja: 'character varying', boja_hex: 'character varying', refill: 'integer', spulna: 'integer', kolicina: 'integer', cena: 'character varying', created_at: 'timestamp with time zone', updated_at: 'timestamp with time zone' } }; describe('Admin Panel Structure', () => { it('should have correct TypeScript interface', () => { // Check Filament interface matches admin structure const filamentKeys: (keyof Filament)[] = [ 'id', 'tip', 'finish', 'boja', 'boja_hex', 'refill', 'spulna', 'kolicina', 'cena', 'status', 'createdAt', 'updatedAt' ]; // Should not have brand expect(filamentKeys).not.toContain('brand'); // Should have all required fields ADMIN_STRUCTURE.requiredFields.forEach(field => { expect(filamentKeys).toContain(field); }); }); it('should have consistent form fields in admin dashboard', () => { const formFields = [ 'tip', 'finish', 'boja', 'boja_hex', 'refill', 'spulna', 'kolicina', 'cena' ]; // Check all form fields are in admin structure formFields.forEach(field => { expect(ADMIN_STRUCTURE.fields).toContain(field); }); // Should not have brand in form expect(formFields).not.toContain('brand'); }); }); describe('Database Schema Consistency', () => { let pool: Pool; beforeAll(() => { pool = new Pool({ connectionString, ssl: { rejectUnauthorized: false } }); }); afterAll(async () => { await pool.end(); }); it('should have correct columns in database', async () => { const result = await pool.query(` SELECT column_name, data_type FROM information_schema.columns WHERE table_name = 'filaments' ORDER BY ordinal_position `); const columns = result.rows.map(row => row.column_name); const columnTypes = result.rows.reduce((acc, row) => { acc[row.column_name] = row.data_type; return acc; }, {} as Record); // Check all expected columns exist DB_STRUCTURE.columns.forEach(col => { expect(columns).toContain(col); }); // Check no excluded columns exist DB_STRUCTURE.excludedColumns.forEach(col => { expect(columns).not.toContain(col); }); // Check column types match Object.entries(DB_STRUCTURE.columnTypes).forEach(([col, type]) => { expect(columnTypes[col]).toBe(type); }); }); it('should not have brand column', async () => { const result = await pool.query(` SELECT COUNT(*) as count FROM information_schema.columns WHERE table_name = 'filaments' AND column_name = 'brand' `); expect(parseInt(result.rows[0].count)).toBe(0); }); }); describe('Frontend Consistency', () => { it('should transform fields correctly between admin and database', () => { // All fields now use snake_case consistently const snakeCaseFields = { 'boja_hex': 'boja_hex', 'created_at': 'created_at', 'updated_at': 'updated_at' }; Object.entries(snakeCaseFields).forEach(([adminField, dbField]) => { expect(ADMIN_STRUCTURE.fields).toContain(adminField); expect(DB_STRUCTURE.columns).toContain(dbField); }); }); it('should handle quantity fields correctly', () => { // Admin form shows refill, spulna as numbers // Database stores them as strings like "2", "1 spulna" const quantityFields = ['refill', 'spulna']; quantityFields.forEach(field => { expect(ADMIN_STRUCTURE.fieldTypes[field]).toBe('number'); expect(DB_STRUCTURE.columnTypes[field]).toBe('integer'); }); }); }); describe('API Consistency', () => { it('should handle requests without brand field', () => { const validRequest = { tip: 'PLA', finish: 'Basic', boja: 'Black', boja_hex: '#000000', refill: '2', spulna: '1 spulna', kolicina: '3', cena: '3999' }; // Should not have brand expect(validRequest).not.toHaveProperty('brand'); // Should have all required fields expect(validRequest).toHaveProperty('tip'); expect(validRequest).toHaveProperty('finish'); expect(validRequest).toHaveProperty('boja'); }); }); describe('Data Flow Consistency', () => { it('should maintain consistent data flow: Admin → API → Database', () => { // Admin form data const adminData = { tip: 'PLA', finish: 'Basic', boja: 'Black', boja_hex: '#000000', refill: '2', spulna: '1 spulna', kolicina: '3', cena: '3999' }; // No transformation needed - using boja_hex consistently const apiData = adminData; // Database expected data expect(apiData).toHaveProperty('boja_hex'); // No longer have bojaHex field expect(apiData).not.toHaveProperty('brand'); }); }); });